/*******************************************************************************
 * KindEditor - WYSIWYG HTML Editor for Internet Copyright (C) 2006-2013
 * kindsoft.net
 * 
 * @author Roddy <luolonghao@gmail.com>
 * @website http://www.kindsoft.net/
 * @licence http://www.kindsoft.net/license.php
 * @version 4.1.10 (2013-11-23)
 ******************************************************************************/
(function(window, undefined) {
	if (window.KindEditor) {
		return;
	}
	if (!window.console) {
		window.console = {};
	}
	if (!console.log) {
		console.log = function() {
		};
	}
	var _VERSION = '4.1.10 (2013-11-23)', _ua = navigator.userAgent
			.toLowerCase(), _IE = _ua.indexOf('msie') > -1
			&& _ua.indexOf('opera') == -1, _NEWIE = _ua.indexOf('msie') == -1
			&& _ua.indexOf('trident') > -1, _GECKO = _ua.indexOf('gecko') > -1
			&& _ua.indexOf('khtml') == -1, _WEBKIT = _ua.indexOf('applewebkit') > -1, _OPERA = _ua
			.indexOf('opera') > -1, _MOBILE = _ua.indexOf('mobile') > -1, _IOS = /ipad|iphone|ipod/
			.test(_ua), _QUIRKS = document.compatMode != 'CSS1Compat', _IERANGE = !window.getSelection, _matches = /(?:msie|firefox|webkit|opera)[\/:\s](\d+)/
			.exec(_ua), _V = _matches ? _matches[1] : '0', _TIME = new Date()
			.getTime();
	function _isArray(val) {
		if (!val) {
			return false;
		}
		return Object.prototype.toString.call(val) === '[object Array]';
	}
	function _isFunction(val) {
		if (!val) {
			return false;
		}
		return Object.prototype.toString.call(val) === '[object Function]';
	}
	function _inArray(val, arr) {
		for (var i = 0, len = arr.length; i < len; i++) {
			if (val === arr[i]) {
				return i;
			}
		}
		return -1;
	}
	function _each(obj, fn) {
		if (_isArray(obj)) {
			for (var i = 0, len = obj.length; i < len; i++) {
				if (fn.call(obj[i], i, obj[i]) === false) {
					break;
				}
			}
		} else {
			for ( var key in obj) {
				if (obj.hasOwnProperty(key)) {
					if (fn.call(obj[key], key, obj[key]) === false) {
						break;
					}
				}
			}
		}
	}
	function _trim(str) {
		return str.replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, '');
	}
	function _inString(val, str, delimiter) {
		delimiter = delimiter === undefined ? ',' : delimiter;
		return (delimiter + str + delimiter).indexOf(delimiter + val
				+ delimiter) >= 0;
	}
	function _addUnit(val, unit) {
		unit = unit || 'px';
		return val && /^\d+$/.test(val) ? val + unit : val;
	}
	function _removeUnit(val) {
		var match;
		return val && (match = /(\d+)/.exec(val)) ? parseInt(match[1], 10) : 0;
	}
	function _escape(val) {
		return val.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g,
				'&gt;').replace(/"/g, '&quot;');
	}
	function _unescape(val) {
		return val.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(
				/&quot;/g, '"').replace(/&amp;/g, '&');
	}
	function _toCamel(str) {
		var arr = str.split('-');
		str = '';
		_each(arr, function(key, val) {
			str += (key > 0) ? val.charAt(0).toUpperCase() + val.substr(1)
					: val;
		});
		return str;
	}
	function _toHex(val) {
		function hex(d) {
			var s = parseInt(d, 10).toString(16).toUpperCase();
			return s.length > 1 ? s : '0' + s;
		}
		return val.replace(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/ig,
				function($0, $1, $2, $3) {
					return '#' + hex($1) + hex($2) + hex($3);
				});
	}
	function _toMap(val, delimiter) {
		delimiter = delimiter === undefined ? ',' : delimiter;
		var map = {}, arr = _isArray(val) ? val : val.split(delimiter), match;
		_each(arr,
				function(key, val) {
					if ((match = /^(\d+)\.\.(\d+)$/.exec(val))) {
						for (var i = parseInt(match[1], 10); i <= parseInt(
								match[2], 10); i++) {
							map[i.toString()] = true;
						}
					} else {
						map[val] = true;
					}
				});
		return map;
	}
	function _toArray(obj, offset) {
		return Array.prototype.slice.call(obj, offset || 0);
	}
	function _undef(val, defaultVal) {
		return val === undefined ? defaultVal : val;
	}
	function _invalidUrl(url) {
		return !url || /[<>"]/.test(url);
	}
	function _addParam(url, param) {
		return url.indexOf('?') >= 0 ? url + '&' + param : url + '?' + param;
	}
	function _extend(child, parent, proto) {
		if (!proto) {
			proto = parent;
			parent = null;
		}
		var childProto;
		if (parent) {
			var fn = function() {
			};
			fn.prototype = parent.prototype;
			childProto = new fn();
			_each(proto, function(key, val) {
				childProto[key] = val;
			});
		} else {
			childProto = proto;
		}
		childProto.constructor = child;
		child.prototype = childProto;
		child.parent = parent ? parent.prototype : null;
	}
	function _json(text) {
		var match;
		if ((match = /\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))) {
			text = match[0];
		}
		var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
		cx.lastIndex = 0;
		if (cx.test(text)) {
			text = text.replace(cx, function(a) {
				return '\\u'
						+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
			});
		}
		if (/^[\],:{}\s]*$/
				.test(text
						.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
						.replace(
								/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
								']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
			return eval('(' + text + ')');
		}
		throw 'JSON parse error';
	}
	var _round = Math.round;
	var K = {
		DEBUG : false,
		VERSION : _VERSION,
		IE : _IE,
		GECKO : _GECKO,
		WEBKIT : _WEBKIT,
		OPERA : _OPERA,
		V : _V,
		TIME : _TIME,
		each : _each,
		isArray : _isArray,
		isFunction : _isFunction,
		inArray : _inArray,
		inString : _inString,
		trim : _trim,
		addUnit : _addUnit,
		removeUnit : _removeUnit,
		escape : _escape,
		unescape : _unescape,
		toCamel : _toCamel,
		toHex : _toHex,
		toMap : _toMap,
		toArray : _toArray,
		undef : _undef,
		invalidUrl : _invalidUrl,
		addParam : _addParam,
		extend : _extend,
		json : _json
	};
	var _INLINE_TAG_MAP = _toMap('a,abbr,acronym,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,img,input,ins,kbd,label,map,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'), _BLOCK_TAG_MAP = _toMap('address,applet,blockquote,body,center,dd,dir,div,dl,dt,fieldset,form,frameset,h1,h2,h3,h4,h5,h6,head,hr,html,iframe,ins,isindex,li,map,menu,meta,noframes,noscript,object,ol,p,pre,script,style,table,tbody,td,tfoot,th,thead,title,tr,ul'), _SINGLE_TAG_MAP = _toMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'), _STYLE_TAG_MAP = _toMap('b,basefont,big,del,em,font,i,s,small,span,strike,strong,sub,sup,u'), _CONTROL_TAG_MAP = _toMap('img,table,input,textarea,button'), _PRE_TAG_MAP = _toMap('pre,style,script'), _NOSPLIT_TAG_MAP = _toMap('html,head,body,td,tr,table,ol,ul,li'), _AUTOCLOSE_TAG_MAP = _toMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'), _FILL_ATTR_MAP = _toMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'), _VALUE_TAG_MAP = _toMap('input,button,textarea,select');
	function _getBasePath() {
		var els = document.getElementsByTagName('script'), src;
		for (var i = 0, len = els.length; i < len; i++) {
			src = els[i].src || '';
			if (/kindeditor[\w\-\.]*\.js/.test(src)) {
				return src.substring(0, src.lastIndexOf('/') + 1);
			}
		}
		return '';
	}
	K.basePath = _getBasePath();
	K.options = {
		designMode : true,
		fullscreenMode : false,
		filterMode : true,
		wellFormatMode : true,
		shadowMode : true,
		loadStyleMode : true,
		basePath : K.basePath,
		themesPath : K.basePath + 'themes/',
		langPath : K.basePath + 'lang/',
		pluginsPath : K.basePath + 'plugins/',
		themeType : 'default',
		langType : 'zh_CN',
		urlType : '',
		newlineTag : 'p',
		resizeType : 2,
		syncType : 'form',
		pasteType : 2,
		dialogAlignType : 'page',
		useContextmenu : true,
		fullscreenShortcut : false,
		bodyClass : 'ke-content',
		indentChar : '\t',
		cssPath : '',
		cssData : '',
		minWidth : 650,
		minHeight : 100,
		minChangeSize : 50,
		zIndex : 811213,
		items : [ 'source', '|', 'undo', 'redo', '|', 'preview', 'print',
				'template', 'code', 'cut', 'copy', 'paste', 'plainpaste',
				'wordpaste', '|', 'justifyleft', 'justifycenter',
				'justifyright', 'justifyfull', 'insertorderedlist',
				'insertunorderedlist', 'indent', 'outdent', 'subscript',
				'superscript', 'clearhtml', 'quickformat', 'selectall', '|',
				'fullscreen', '/', 'formatblock', 'fontname', 'fontsize', '|',
				'forecolor', 'hilitecolor', 'bold', 'italic', 'underline',
				'strikethrough', 'lineheight', 'removeformat', '|', 'image',
				'multiimage', 'flash', 'media', 'insertfile', 'table', 'hr',
				'emoticons', 'baidumap', 'pagebreak', 'anchor', 'link',
				'unlink', '|', 'about' ],
		noDisableItems : [ 'source', 'fullscreen' ],
		colorTable : [
				[ '#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4',
						'#FFE500' ],
				[ '#009900', '#006600', '#99BB00', '#B8D100', '#60D978',
						'#00D5FF' ],
				[ '#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5',
						'#EE33EE' ],
				[ '#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333',
						'#000000' ] ],
		fontSizeTable : [ '9px', '10px', '12px', '14px', '16px', '18px',
				'24px', '32px' ],
		htmlTags : {
			font : [ 'id', 'class', 'color', 'size', 'face',
					'.background-color' ],
			span : [ 'id', 'class', '.color', '.background-color',
					'.font-size', '.font-family', '.background',
					'.font-weight', '.font-style', '.text-decoration',
					'.vertical-align', '.line-height' ],
			div : [ 'id', 'class', 'align', '.border', '.margin', '.padding',
					'.text-align', '.color', '.background-color', '.font-size',
					'.font-family', '.font-weight', '.background',
					'.font-style', '.text-decoration', '.vertical-align',
					'.margin-left' ],
			table : [ 'id', 'class', 'border', 'cellspacing', 'cellpadding',
					'width', 'height', 'align', 'bordercolor', '.padding',
					'.margin', '.border', 'bgcolor', '.text-align', '.color',
					'.background-color', '.font-size', '.font-family',
					'.font-weight', '.font-style', '.text-decoration',
					'.background', '.width', '.height', '.border-collapse' ],
			'td,th' : [ 'id', 'class', 'align', 'valign', 'width', 'height',
					'colspan', 'rowspan', 'bgcolor', '.text-align', '.color',
					'.background-color', '.font-size', '.font-family',
					'.font-weight', '.font-style', '.text-decoration',
					'.vertical-align', '.background', '.border' ],
			a : [ 'id', 'class', 'href', 'target', 'name' ],
			embed : [ 'id', 'class', 'src', 'width', 'height', 'type', 'loop',
					'autostart', 'quality', '.width', '.height', 'align',
					'allowscriptaccess' ],
			img : [ 'id', 'class', 'src', 'width', 'height', 'border', 'alt',
					'title', 'align', '.width', '.height', '.border' ],
			'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6' : [ 'id', 'class',
					'align', '.text-align', '.color', '.background-color',
					'.font-size', '.font-family', '.background',
					'.font-weight', '.font-style', '.text-decoration',
					'.vertical-align', '.text-indent', '.margin-left' ],
			pre : [ 'id', 'class' ],
			hr : [ 'id', 'class', '.page-break-after' ],
			'br,tbody,tr,strong,b,sub,sup,em,i,u,strike,s,del' : [ 'id',
					'class' ],
			iframe : [ 'id', 'class', 'src', 'frameborder', 'width', 'height',
					'.width', '.height' ]
		},
		layout : '<div class="container"><div class="toolbar"></div><div class="edit"></div><div class="statusbar"></div></div>'
	};
	var _useCapture = false;
	var _INPUT_KEY_MAP = _toMap('8,9,13,32,46,48..57,59,61,65..90,106,109..111,188,190..192,219..222');
	var _CURSORMOVE_KEY_MAP = _toMap('33..40');
	var _CHANGE_KEY_MAP = {};
	_each(_INPUT_KEY_MAP, function(key, val) {
		_CHANGE_KEY_MAP[key] = val;
	});
	_each(_CURSORMOVE_KEY_MAP, function(key, val) {
		_CHANGE_KEY_MAP[key] = val;
	});
	function _bindEvent(el, type, fn) {
		if (el.addEventListener) {
			el.addEventListener(type, fn, _useCapture);
		} else if (el.attachEvent) {
			el.attachEvent('on' + type, fn);
		}
	}
	function _unbindEvent(el, type, fn) {
		if (el.removeEventListener) {
			el.removeEventListener(type, fn, _useCapture);
		} else if (el.detachEvent) {
			el.detachEvent('on' + type, fn);
		}
	}
	var _EVENT_PROPS = ('altKey,attrChange,attrName,bubbles,button,cancelable,charCode,clientX,clientY,ctrlKey,currentTarget,'
			+ 'data,detail,eventPhase,fromElement,handler,keyCode,metaKey,newValue,offsetX,offsetY,originalTarget,pageX,'
			+ 'pageY,prevValue,relatedNode,relatedTarget,screenX,screenY,shiftKey,srcElement,target,toElement,view,wheelDelta,which')
			.split(',');
	function KEvent(el, event) {
		this.init(el, event);
	}
	_extend(
			KEvent,
			{
				init : function(el, event) {
					var self = this, doc = el.ownerDocument || el.document
							|| el;
					self.event = event;
					_each(_EVENT_PROPS, function(key, val) {
						self[val] = event[val];
					});
					if (!self.target) {
						self.target = self.srcElement || doc;
					}
					if (self.target.nodeType === 3) {
						self.target = self.target.parentNode;
					}
					if (!self.relatedTarget && self.fromElement) {
						self.relatedTarget = self.fromElement === self.target ? self.toElement
								: self.fromElement;
					}
					if (self.pageX == null && self.clientX != null) {
						var d = doc.documentElement, body = doc.body;
						self.pageX = self.clientX
								+ (d && d.scrollLeft || body && body.scrollLeft || 0)
								- (d && d.clientLeft || body && body.clientLeft || 0);
						self.pageY = self.clientY
								+ (d && d.scrollTop || body && body.scrollTop || 0)
								- (d && d.clientTop || body && body.clientTop || 0);
					}
					if (!self.which
							&& ((self.charCode || self.charCode === 0) ? self.charCode
									: self.keyCode)) {
						self.which = self.charCode || self.keyCode;
					}
					if (!self.metaKey && self.ctrlKey) {
						self.metaKey = self.ctrlKey;
					}
					if (!self.which && self.button !== undefined) {
						self.which = (self.button & 1 ? 1
								: (self.button & 2 ? 3 : (self.button & 4 ? 2
										: 0)));
					}
					switch (self.which) {
					case 186:
						self.which = 59;
						break;
					case 187:
					case 107:
					case 43:
						self.which = 61;
						break;
					case 189:
					case 45:
						self.which = 109;
						break;
					case 42:
						self.which = 106;
						break;
					case 47:
						self.which = 111;
						break;
					case 78:
						self.which = 110;
						break;
					}
					if (self.which >= 96 && self.which <= 105) {
						self.which -= 48;
					}
				},
				preventDefault : function() {
					var ev = this.event;
					if (ev.preventDefault) {
						ev.preventDefault();
					} else {
						ev.returnValue = false;
					}
				},
				stopPropagation : function() {
					var ev = this.event;
					if (ev.stopPropagation) {
						ev.stopPropagation();
					} else {
						ev.cancelBubble = true;
					}
				},
				stop : function() {
					this.preventDefault();
					this.stopPropagation();
				}
			});
	var _eventExpendo = 'kindeditor_' + _TIME, _eventId = 0, _eventData = {};
	function _getId(el) {
		return el[_eventExpendo] || null;
	}
	function _setId(el) {
		el[_eventExpendo] = ++_eventId;
		return _eventId;
	}
	function _removeId(el) {
		try {
			delete el[_eventExpendo];
		} catch (e) {
			if (el.removeAttribute) {
				el.removeAttribute(_eventExpendo);
			}
		}
	}
	function _bind(el, type, fn) {
		if (type.indexOf(',') >= 0) {
			_each(type.split(','), function() {
				_bind(el, this, fn);
			});
			return;
		}
		var id = _getId(el);
		if (!id) {
			id = _setId(el);
		}
		if (_eventData[id] === undefined) {
			_eventData[id] = {};
		}
		var events = _eventData[id][type];
		if (events && events.length > 0) {
			_unbindEvent(el, type, events[0]);
		} else {
			_eventData[id][type] = [];
			_eventData[id].el = el;
		}
		events = _eventData[id][type];
		if (events.length === 0) {
			events[0] = function(e) {
				var kevent = e ? new KEvent(el, e) : undefined;
				_each(events, function(i, event) {
					if (i > 0 && event) {
						event.call(el, kevent);
					}
				});
			};
		}
		if (_inArray(fn, events) < 0) {
			events.push(fn);
		}
		_bindEvent(el, type, events[0]);
	}
	function _unbind(el, type, fn) {
		if (type && type.indexOf(',') >= 0) {
			_each(type.split(','), function() {
				_unbind(el, this, fn);
			});
			return;
		}
		var id = _getId(el);
		if (!id) {
			return;
		}
		if (type === undefined) {
			if (id in _eventData) {
				_each(_eventData[id], function(key, events) {
					if (key != 'el' && events.length > 0) {
						_unbindEvent(el, key, events[0]);
					}
				});
				delete _eventData[id];
				_removeId(el);
			}
			return;
		}
		if (!_eventData[id]) {
			return;
		}
		var events = _eventData[id][type];
		if (events && events.length > 0) {
			if (fn === undefined) {
				_unbindEvent(el, type, events[0]);
				delete _eventData[id][type];
			} else {
				_each(events, function(i, event) {
					if (i > 0 && event === fn) {
						events.splice(i, 1);
					}
				});
				if (events.length == 1) {
					_unbindEvent(el, type, events[0]);
					delete _eventData[id][type];
				}
			}
			var count = 0;
			_each(_eventData[id], function() {
				count++;
			});
			if (count < 2) {
				delete _eventData[id];
				_removeId(el);
			}
		}
	}
	function _fire(el, type) {
		if (type.indexOf(',') >= 0) {
			_each(type.split(','), function() {
				_fire(el, this);
			});
			return;
		}
		var id = _getId(el);
		if (!id) {
			return;
		}
		var events = _eventData[id][type];
		if (_eventData[id] && events && events.length > 0) {
			events[0]();
		}
	}
	function _ctrl(el, key, fn) {
		var self = this;
		key = /^\d{2,}$/.test(key) ? key : key.toUpperCase().charCodeAt(0);
		_bind(el, 'keydown', function(e) {
			if (e.ctrlKey && e.which == key && !e.shiftKey && !e.altKey) {
				fn.call(el);
				e.stop();
			}
		});
	}
	var _readyFinished = false;
	function _ready(fn) {
		if (_readyFinished) {
			fn(KindEditor);
			return;
		}
		var loaded = false;
		function readyFunc() {
			if (!loaded) {
				loaded = true;
				fn(KindEditor);
				_readyFinished = true;
			}
		}
		function ieReadyFunc() {
			if (!loaded) {
				try {
					document.documentElement.doScroll('left');
				} catch (e) {
					setTimeout(ieReadyFunc, 100);
					return;
				}
				readyFunc();
			}
		}
		function ieReadyStateFunc() {
			if (document.readyState === 'complete') {
				readyFunc();
			}
		}
		if (document.addEventListener) {
			_bind(document, 'DOMContentLoaded', readyFunc);
		} else if (document.attachEvent) {
			_bind(document, 'readystatechange', ieReadyStateFunc);
			var toplevel = false;
			try {
				toplevel = window.frameElement == null;
			} catch (e) {
			}
			if (document.documentElement.doScroll && toplevel) {
				ieReadyFunc();
			}
		}
		_bind(window, 'load', readyFunc);
	}
	if (_IE) {
		window.attachEvent('onunload', function() {
			_each(_eventData, function(key, events) {
				if (events.el) {
					_unbind(events.el);
				}
			});
		});
	}
	K.ctrl = _ctrl;
	K.ready = _ready;
	function _getCssList(css) {
		var list = {}, reg = /\s*([\w\-]+)\s*:([^;]*)(;|$)/g, match;
		while ((match = reg.exec(css))) {
			var key = _trim(match[1].toLowerCase()), val = _trim(_toHex(match[2]));
			list[key] = val;
		}
		return list;
	}
	function _getAttrList(tag) {
		var list = {}, reg = /\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g, match;
		while ((match = reg.exec(tag))) {
			var key = (match[1] || match[2] || match[4] || match[6])
					.toLowerCase(), val = (match[2] ? match[3]
					: (match[4] ? match[5] : match[7]))
					|| '';
			list[key] = val;
		}
		return list;
	}
	function _addClassToTag(tag, className) {
		if (/\s+class\s*=/.test(tag)) {
			tag = tag.replace(/(\s+class=["']?)([^"']*)(["']?[\s>])/, function(
					$0, $1, $2, $3) {
				if ((' ' + $2 + ' ').indexOf(' ' + className + ' ') < 0) {
					return $2 === '' ? $1 + className + $3 : $1 + $2 + ' '
							+ className + $3;
				} else {
					return $0;
				}
			});
		} else {
			tag = tag.substr(0, tag.length - 1) + ' class="' + className + '">';
		}
		return tag;
	}
	function _formatCss(css) {
		var str = '';
		_each(_getCssList(css), function(key, val) {
			str += key + ':' + val + ';';
		});
		return str;
	}
	function _formatUrl(url, mode, host, pathname) {
		mode = _undef(mode, '').toLowerCase();
		if (url.substr(0, 5) != 'data:') {
			url = url.replace(/([^:])\/\//g, '$1/');
		}
		if (_inArray(mode, [ 'absolute', 'relative', 'domain' ]) < 0) {
			return url;
		}
		host = host || location.protocol + '//' + location.host;
		if (pathname === undefined) {
			var m = location.pathname.match(/^(\/.*)\//);
			pathname = m ? m[1] : '';
		}
		var match;
		if ((match = /^(\w+:\/\/[^\/]*)/.exec(url))) {
			if (match[1] !== host) {
				return url;
			}
		} else if (/^\w+:/.test(url)) {
			return url;
		}
		function getRealPath(path) {
			var parts = path.split('/'), paths = [];
			for (var i = 0, len = parts.length; i < len; i++) {
				var part = parts[i];
				if (part == '..') {
					if (paths.length > 0) {
						paths.pop();
					}
				} else if (part !== '' && part != '.') {
					paths.push(part);
				}
			}
			return '/' + paths.join('/');
		}
		if (/^\//.test(url)) {
			url = host + getRealPath(url.substr(1));
		} else if (!/^\w+:\/\//.test(url)) {
			url = host + getRealPath(pathname + '/' + url);
		}
		function getRelativePath(path, depth) {
			if (url.substr(0, path.length) === path) {
				var arr = [];
				for (var i = 0; i < depth; i++) {
					arr.push('..');
				}
				var prefix = '.';
				if (arr.length > 0) {
					prefix += '/' + arr.join('/');
				}
				if (pathname == '/') {
					prefix += '/';
				}
				return prefix + url.substr(path.length);
			} else {
				if ((match = /^(.*)\//.exec(path))) {
					return getRelativePath(match[1], ++depth);
				}
			}
		}
		if (mode === 'relative') {
			url = getRelativePath(host + pathname, 0).substr(2);
		} else if (mode === 'absolute') {
			if (url.substr(0, host.length) === host) {
				url = url.substr(host.length);
			}
		}
		return url;
	}
	function _formatHtml(html, htmlTags, urlType, wellFormatted, indentChar) {
		if (html == null) {
			html = '';
		}
		urlType = urlType || '';
		wellFormatted = _undef(wellFormatted, false);
		indentChar = _undef(indentChar, '\t');
		var fontSizeList = 'xx-small,x-small,small,medium,large,x-large,xx-large'
				.split(',');
		html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig,
				function($0, $1, $2, $3) {
					return $1 + $2.replace(/<(?:br|br\s[^>]*)>/ig, '\n') + $3;
				});
		html = html.replace(/<(?:br|br\s[^>]*)\s*\/?>\s*<\/p>/ig, '</p>');
		html = html.replace(/(<(?:p|p\s[^>]*)>)\s*(<\/p>)/ig, '$1<br />$2');
		html = html.replace(/\u200B/g, '');
		html = html.replace(/\u00A9/g, '&copy;');
		html = html.replace(/\u00AE/g, '&reg;');
		html = html.replace(/<[^>]+/g, function($0) {
			return $0.replace(/\s+/g, ' ');
		});
		var htmlTagMap = {};
		if (htmlTags) {
			_each(htmlTags, function(key, val) {
				var arr = key.split(',');
				for (var i = 0, len = arr.length; i < len; i++) {
					htmlTagMap[arr[i]] = _toMap(val);
				}
			});
			if (!htmlTagMap.script) {
				html = html.replace(
						/(<(?:script|script\s[^>]*)>)([\s\S]*?)(<\/script>)/ig,
						'');
			}
			if (!htmlTagMap.style) {
				html = html
						.replace(
								/(<(?:style|style\s[^>]*)>)([\s\S]*?)(<\/style>)/ig,
								'');
			}
		}
		var re = /(\s*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>(\s*)/g;
		var tagStack = [];
		html = html
				.replace(
						re,
						function($0, $1, $2, $3, $4, $5, $6) {
							var full = $0, startNewline = $1 || '', startSlash = $2
									|| '', tagName = $3.toLowerCase(), attr = $4
									|| '', endSlash = $5 ? ' ' + $5 : '', endNewline = $6
									|| '';
							if (htmlTags && !htmlTagMap[tagName]) {
								return '';
							}
							if (endSlash === '' && _SINGLE_TAG_MAP[tagName]) {
								endSlash = ' /';
							}
							if (_INLINE_TAG_MAP[tagName]) {
								if (startNewline) {
									startNewline = ' ';
								}
								if (endNewline) {
									endNewline = ' ';
								}
							}
							if (_PRE_TAG_MAP[tagName]) {
								if (startSlash) {
									endNewline = '\n';
								} else {
									startNewline = '\n';
								}
							}
							if (wellFormatted && tagName == 'br') {
								endNewline = '\n';
							}
							if (_BLOCK_TAG_MAP[tagName]
									&& !_PRE_TAG_MAP[tagName]) {
								if (wellFormatted) {
									if (startSlash
											&& tagStack.length > 0
											&& tagStack[tagStack.length - 1] === tagName) {
										tagStack.pop();
									} else {
										tagStack.push(tagName);
									}
									startNewline = '\n';
									endNewline = '\n';
									for (var i = 0, len = startSlash ? tagStack.length
											: tagStack.length - 1; i < len; i++) {
										startNewline += indentChar;
										if (!startSlash) {
											endNewline += indentChar;
										}
									}
									if (endSlash) {
										tagStack.pop();
									} else if (!startSlash) {
										endNewline += indentChar;
									}
								} else {
									startNewline = endNewline = '';
								}
							}
							if (attr !== '') {
								var attrMap = _getAttrList(full);
								if (tagName === 'font') {
									var fontStyleMap = {}, fontStyle = '';
									_each(
											attrMap,
											function(key, val) {
												if (key === 'color') {
													fontStyleMap.color = val;
													delete attrMap[key];
												}
												if (key === 'size') {
													fontStyleMap['font-size'] = fontSizeList[parseInt(
															val, 10) - 1]
															|| '';
													delete attrMap[key];
												}
												if (key === 'face') {
													fontStyleMap['font-family'] = val;
													delete attrMap[key];
												}
												if (key === 'style') {
													fontStyle = val;
												}
											});
									if (fontStyle && !/;$/.test(fontStyle)) {
										fontStyle += ';';
									}
									_each(fontStyleMap, function(key, val) {
										if (val === '') {
											return;
										}
										if (/\s/.test(val)) {
											val = "'" + val + "'";
										}
										fontStyle += key + ':' + val + ';';
									});
									attrMap.style = fontStyle;
								}
								_each(
										attrMap,
										function(key, val) {
											if (_FILL_ATTR_MAP[key]) {
												attrMap[key] = key;
											}
											if (_inArray(key, [ 'src', 'href' ]) >= 0) {
												attrMap[key] = _formatUrl(val,
														urlType);
											}
											if (htmlTags
													&& key !== 'style'
													&& !htmlTagMap[tagName]['*']
													&& !htmlTagMap[tagName][key]
													|| tagName === 'body'
													&& key === 'contenteditable'
													|| /^kindeditor_\d+$/
															.test(key)) {
												delete attrMap[key];
											}
											if (key === 'style' && val !== '') {
												var styleMap = _getCssList(val);
												_each(
														styleMap,
														function(k, v) {
															if (htmlTags
																	&& !htmlTagMap[tagName].style
																	&& !htmlTagMap[tagName]['.'
																			+ k]) {
																delete styleMap[k];
															}
														});
												var style = '';
												_each(styleMap, function(k, v) {
													style += k + ':' + v + ';';
												});
												attrMap.style = style;
											}
										});
								attr = '';
								_each(attrMap, function(key, val) {
									if (key === 'style' && val === '') {
										return;
									}
									val = val.replace(/"/g, '&quot;');
									attr += ' ' + key + '="' + val + '"';
								});
							}
							if (tagName === 'font') {
								tagName = 'span';
							}
							return startNewline + '<' + startSlash + tagName
									+ attr + endSlash + '>' + endNewline;
						});
		html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig,
				function($0, $1, $2, $3) {
					return $1
							+ $2.replace(/\n/g,
									'<span id="__kindeditor_pre_newline__">\n')
							+ $3;
				});
		html = html.replace(/\n\s*\n/g, '\n');
		html = html.replace(/<span id="__kindeditor_pre_newline__">\n/g, '\n');
		return _trim(html);
	}
	function _clearMsWord(html, htmlTags) {
		html = html.replace(/<meta[\s\S]*?>/ig, '')
				.replace(/<![\s\S]*?>/ig, '').replace(
						/<style[^>]*>[\s\S]*?<\/style>/ig, '').replace(
						/<script[^>]*>[\s\S]*?<\/script>/ig, '').replace(
						/<w:[^>]+>[\s\S]*?<\/w:[^>]+>/ig, '').replace(
						/<o:[^>]+>[\s\S]*?<\/o:[^>]+>/ig, '').replace(
						/<xml>[\s\S]*?<\/xml>/ig, '').replace(
						/<(?:table|td)[^>]*>/ig,
						function(full) {
							return full.replace(/border-bottom:([#\w\s]+)/ig,
									'border:$1');
						});
		return _formatHtml(html, htmlTags);
	}
	function _mediaType(src) {
		if (/\.(rm|rmvb)(\?|$)/i.test(src)) {
			return 'audio/x-pn-realaudio-plugin';
		}
		if (/\.(swf|flv)(\?|$)/i.test(src)) {
			return 'application/x-shockwave-flash';
		}
		return 'video/x-ms-asf-plugin';
	}
	function _mediaClass(type) {
		if (/realaudio/i.test(type)) {
			return 'ke-rm';
		}
		if (/flash/i.test(type)) {
			return 'ke-flash';
		}
		return 'ke-media';
	}
	function _mediaAttrs(srcTag) {
		return _getAttrList(unescape(srcTag));
	}
	function _mediaEmbed(attrs) {
		var html = '<embed ';
		_each(attrs, function(key, val) {
			html += key + '="' + val + '" ';
		});
		html += '/>';
		return html;
	}
	function _mediaImg(blankPath, attrs) {
		var width = attrs.width, height = attrs.height, type = attrs.type
				|| _mediaType(attrs.src), srcTag = _mediaEmbed(attrs), style = '';
		if (/\D/.test(width)) {
			style += 'width:' + width + ';';
		} else if (width > 0) {
			style += 'width:' + width + 'px;';
		}
		if (/\D/.test(height)) {
			style += 'height:' + height + ';';
		} else if (height > 0) {
			style += 'height:' + height + 'px;';
		}
		var html = '<img class="' + _mediaClass(type) + '" src="' + blankPath
				+ '" ';
		if (style !== '') {
			html += 'style="' + style + '" ';
		}
		html += 'data-ke-tag="' + escape(srcTag) + '" alt="" />';
		return html;
	}
	function _tmpl(str, data) {
		var fn = new Function("obj",
				"var p=[],print=function(){p.push.apply(p,arguments);};"
						+ "with(obj){p.push('"
						+ str.replace(/[\r\t\n]/g, " ").split("<%").join("\t")
								.replace(/((^|%>)[^\t]*)'/g, "$1\r").replace(
										/\t=(.*?)%>/g, "',$1,'").split("\t")
								.join("');").split("%>").join("p.push('")
								.split("\r").join("\\'")
						+ "');}return p.join('');");
		return data ? fn(data) : fn;
	}
	K.formatUrl = _formatUrl;
	K.formatHtml = _formatHtml;
	K.getCssList = _getCssList;
	K.getAttrList = _getAttrList;
	K.mediaType = _mediaType;
	K.mediaAttrs = _mediaAttrs;
	K.mediaEmbed = _mediaEmbed;
	K.mediaImg = _mediaImg;
	K.clearMsWord = _clearMsWord;
	K.tmpl = _tmpl;
	function _contains(nodeA, nodeB) {
		if (nodeA.nodeType == 9 && nodeB.nodeType != 9) {
			return true;
		}
		while ((nodeB = nodeB.parentNode)) {
			if (nodeB == nodeA) {
				return true;
			}
		}
		return false;
	}
	var _getSetAttrDiv = document.createElement('div');
	_getSetAttrDiv.setAttribute('className', 't');
	var _GET_SET_ATTRIBUTE = _getSetAttrDiv.className !== 't';
	function _getAttr(el, key) {
		key = key.toLowerCase();
		var val = null;
		if (!_GET_SET_ATTRIBUTE && el.nodeName.toLowerCase() != 'script') {
			var div = el.ownerDocument.createElement('div');
			div.appendChild(el.cloneNode(false));
			var list = _getAttrList(_unescape(div.innerHTML));
			if (key in list) {
				val = list[key];
			}
		} else {
			try {
				val = el.getAttribute(key, 2);
			} catch (e) {
				val = el.getAttribute(key, 1);
			}
		}
		if (key === 'style' && val !== null) {
			val = _formatCss(val);
		}
		return val;
	}
	function _queryAll(expr, root) {
		var exprList = expr.split(',');
		if (exprList.length > 1) {
			var mergedResults = [];
			_each(exprList, function() {
				_each(_queryAll(this, root), function() {
					if (_inArray(this, mergedResults) < 0) {
						mergedResults.push(this);
					}
				});
			});
			return mergedResults;
		}
		root = root || document;
		function escape(str) {
			if (typeof str != 'string') {
				return str;
			}
			return str.replace(/([^\w\-])/g, '\\$1');
		}
		function stripslashes(str) {
			return str.replace(/\\/g, '');
		}
		function cmpTag(tagA, tagB) {
			return tagA === '*'
					|| tagA.toLowerCase() === escape(tagB.toLowerCase());
		}
		function byId(id, tag, root) {
			var arr = [], doc = root.ownerDocument || root, el = doc
					.getElementById(stripslashes(id));
			if (el) {
				if (cmpTag(tag, el.nodeName) && _contains(root, el)) {
					arr.push(el);
				}
			}
			return arr;
		}
		function byClass(className, tag, root) {
			var doc = root.ownerDocument || root, arr = [], els, i, len, el;
			if (root.getElementsByClassName) {
				els = root.getElementsByClassName(stripslashes(className));
				for (i = 0, len = els.length; i < len; i++) {
					el = els[i];
					if (cmpTag(tag, el.nodeName)) {
						arr.push(el);
					}
				}
			} else if (doc.querySelectorAll) {
				els = doc
						.querySelectorAll((root.nodeName !== '#document' ? root.nodeName
								+ ' '
								: '')
								+ tag + '.' + className);
				for (i = 0, len = els.length; i < len; i++) {
					el = els[i];
					if (_contains(root, el)) {
						arr.push(el);
					}
				}
			} else {
				els = root.getElementsByTagName(tag);
				className = ' ' + className + ' ';
				for (i = 0, len = els.length; i < len; i++) {
					el = els[i];
					if (el.nodeType == 1) {
						var cls = el.className;
						if (cls && (' ' + cls + ' ').indexOf(className) > -1) {
							arr.push(el);
						}
					}
				}
			}
			return arr;
		}
		function byName(name, tag, root) {
			var arr = [], doc = root.ownerDocument || root, els = doc
					.getElementsByName(stripslashes(name)), el;
			for (var i = 0, len = els.length; i < len; i++) {
				el = els[i];
				if (cmpTag(tag, el.nodeName) && _contains(root, el)) {
					if (el.getAttribute('name') !== null) {
						arr.push(el);
					}
				}
			}
			return arr;
		}
		function byAttr(key, val, tag, root) {
			var arr = [], els = root.getElementsByTagName(tag), el;
			for (var i = 0, len = els.length; i < len; i++) {
				el = els[i];
				if (el.nodeType == 1) {
					if (val === null) {
						if (_getAttr(el, key) !== null) {
							arr.push(el);
						}
					} else {
						if (val === escape(_getAttr(el, key))) {
							arr.push(el);
						}
					}
				}
			}
			return arr;
		}
		function select(expr, root) {
			var arr = [], matches;
			matches = /^((?:\\.|[^.#\s\[<>])+)/.exec(expr);
			var tag = matches ? matches[1] : '*';
			if ((matches = /#((?:[\w\-]|\\.)+)$/.exec(expr))) {
				arr = byId(matches[1], tag, root);
			} else if ((matches = /\.((?:[\w\-]|\\.)+)$/.exec(expr))) {
				arr = byClass(matches[1], tag, root);
			} else if ((matches = /\[((?:[\w\-]|\\.)+)\]/.exec(expr))) {
				arr = byAttr(matches[1].toLowerCase(), null, tag, root);
			} else if ((matches = /\[((?:[\w\-]|\\.)+)\s*=\s*['"]?((?:\\.|[^'"]+)+)['"]?\]/
					.exec(expr))) {
				var key = matches[1].toLowerCase(), val = matches[2];
				if (key === 'id') {
					arr = byId(val, tag, root);
				} else if (key === 'class') {
					arr = byClass(val, tag, root);
				} else if (key === 'name') {
					arr = byName(val, tag, root);
				} else {
					arr = byAttr(key, val, tag, root);
				}
			} else {
				var els = root.getElementsByTagName(tag), el;
				for (var i = 0, len = els.length; i < len; i++) {
					el = els[i];
					if (el.nodeType == 1) {
						arr.push(el);
					}
				}
			}
			return arr;
		}
		var parts = [], arr, re = /((?:\\.|[^\s>])+|[\s>])/g;
		while ((arr = re.exec(expr))) {
			if (arr[1] !== ' ') {
				parts.push(arr[1]);
			}
		}
		var results = [];
		if (parts.length == 1) {
			return select(parts[0], root);
		}
		var isChild = false, part, els, subResults, val, v, i, j, k, length, len, l;
		for (i = 0, lenth = parts.length; i < lenth; i++) {
			part = parts[i];
			if (part === '>') {
				isChild = true;
				continue;
			}
			if (i > 0) {
				els = [];
				for (j = 0, len = results.length; j < len; j++) {
					val = results[j];
					subResults = select(part, val);
					for (k = 0, l = subResults.length; k < l; k++) {
						v = subResults[k];
						if (isChild) {
							if (val === v.parentNode) {
								els.push(v);
							}
						} else {
							els.push(v);
						}
					}
				}
				results = els;
			} else {
				results = select(part, root);
			}
			if (results.length === 0) {
				return [];
			}
		}
		return results;
	}
	function _query(expr, root) {
		var arr = _queryAll(expr, root);
		return arr.length > 0 ? arr[0] : null;
	}
	K.query = _query;
	K.queryAll = _queryAll;
	function _get(val) {
		return K(val)[0];
	}
	function _getDoc(node) {
		if (!node) {
			return document;
		}
		return node.ownerDocument || node.document || node;
	}
	function _getWin(node) {
		if (!node) {
			return window;
		}
		var doc = _getDoc(node);
		return doc.parentWindow || doc.defaultView;
	}
	function _setHtml(el, html) {
		if (el.nodeType != 1) {
			return;
		}
		var doc = _getDoc(el);
		try {
			el.innerHTML = '<img id="__kindeditor_temp_tag__" width="0" height="0" style="display:none;" />'
					+ html;
			var temp = doc.getElementById('__kindeditor_temp_tag__');
			temp.parentNode.removeChild(temp);
		} catch (e) {
			K(el).empty();
			K('@' + html, doc).each(function() {
				el.appendChild(this);
			});
		}
	}
	function _hasClass(el, cls) {
		return _inString(cls, el.className, ' ');
	}
	function _setAttr(el, key, val) {
		if (_IE && _V < 8 && key.toLowerCase() == 'class') {
			key = 'className';
		}
		el.setAttribute(key, '' + val);
	}
	function _removeAttr(el, key) {
		if (_IE && _V < 8 && key.toLowerCase() == 'class') {
			key = 'className';
		}
		_setAttr(el, key, '');
		el.removeAttribute(key);
	}
	function _getNodeName(node) {
		if (!node || !node.nodeName) {
			return '';
		}
		return node.nodeName.toLowerCase();
	}
	function _computedCss(el, key) {
		var self = this, win = _getWin(el), camelKey = _toCamel(key), val = '';
		if (win.getComputedStyle) {
			var style = win.getComputedStyle(el, null);
			val = style[camelKey] || style.getPropertyValue(key)
					|| el.style[camelKey];
		} else if (el.currentStyle) {
			val = el.currentStyle[camelKey] || el.style[camelKey];
		}
		return val;
	}
	function _hasVal(node) {
		return !!_VALUE_TAG_MAP[_getNodeName(node)];
	}
	function _docElement(doc) {
		doc = doc || document;
		return _QUIRKS ? doc.body : doc.documentElement;
	}
	function _docHeight(doc) {
		var el = _docElement(doc);
		return Math.max(el.scrollHeight, el.clientHeight);
	}
	function _docWidth(doc) {
		var el = _docElement(doc);
		return Math.max(el.scrollWidth, el.clientWidth);
	}
	function _getScrollPos(doc) {
		doc = doc || document;
		var x, y;
		if (_IE || _NEWIE || _OPERA) {
			x = _docElement(doc).scrollLeft;
			y = _docElement(doc).scrollTop;
		} else {
			x = _getWin(doc).scrollX;
			y = _getWin(doc).scrollY;
		}
		return {
			x : x,
			y : y
		};
	}
	function KNode(node) {
		this.init(node);
	}
	_extend(
			KNode,
			{
				init : function(node) {
					var self = this;
					node = _isArray(node) ? node : [ node ];
					var length = 0;
					for (var i = 0, len = node.length; i < len; i++) {
						if (node[i]) {
							self[i] = node[i].constructor === KNode ? node[i][0]
									: node[i];
							length++;
						}
					}
					self.length = length;
					self.doc = _getDoc(self[0]);
					self.name = _getNodeName(self[0]);
					self.type = self.length > 0 ? self[0].nodeType : null;
					self.win = _getWin(self[0]);
				},
				each : function(fn) {
					var self = this;
					for (var i = 0; i < self.length; i++) {
						if (fn.call(self[i], i, self[i]) === false) {
							return self;
						}
					}
					return self;
				},
				bind : function(type, fn) {
					this.each(function() {
						_bind(this, type, fn);
					});
					return this;
				},
				unbind : function(type, fn) {
					this.each(function() {
						_unbind(this, type, fn);
					});
					return this;
				},
				fire : function(type) {
					if (this.length < 1) {
						return this;
					}
					_fire(this[0], type);
					return this;
				},
				hasAttr : function(key) {
					if (this.length < 1) {
						return false;
					}
					return !!_getAttr(this[0], key);
				},
				attr : function(key, val) {
					var self = this;
					if (key === undefined) {
						return _getAttrList(self.outer());
					}
					if (typeof key === 'object') {
						_each(key, function(k, v) {
							self.attr(k, v);
						});
						return self;
					}
					if (val === undefined) {
						val = self.length < 1 ? null : _getAttr(self[0], key);
						return val === null ? '' : val;
					}
					self.each(function() {
						_setAttr(this, key, val);
					});
					return self;
				},
				removeAttr : function(key) {
					this.each(function() {
						_removeAttr(this, key);
					});
					return this;
				},
				get : function(i) {
					if (this.length < 1) {
						return null;
					}
					return this[i || 0];
				},
				eq : function(i) {
					if (this.length < 1) {
						return null;
					}
					return this[i] ? new KNode(this[i]) : null;
				},
				hasClass : function(cls) {
					if (this.length < 1) {
						return false;
					}
					return _hasClass(this[0], cls);
				},
				addClass : function(cls) {
					this.each(function() {
						if (!_hasClass(this, cls)) {
							this.className = _trim(this.className + ' ' + cls);
						}
					});
					return this;
				},
				removeClass : function(cls) {
					this.each(function() {
						if (_hasClass(this, cls)) {
							this.className = _trim(this.className.replace(
									new RegExp('(^|\\s)' + cls + '(\\s|$)'),
									' '));
						}
					});
					return this;
				},
				html : function(val) {
					var self = this;
					if (val === undefined) {
						if (self.length < 1 || self.type != 1) {
							return '';
						}
						return _formatHtml(self[0].innerHTML);
					}
					self.each(function() {
						_setHtml(this, val);
					});
					return self;
				},
				text : function() {
					var self = this;
					if (self.length < 1) {
						return '';
					}
					return _IE ? self[0].innerText : self[0].textContent;
				},
				hasVal : function() {
					if (this.length < 1) {
						return false;
					}
					return _hasVal(this[0]);
				},
				val : function(val) {
					var self = this;
					if (val === undefined) {
						if (self.length < 1) {
							return '';
						}
						return self.hasVal() ? self[0].value : self
								.attr('value');
					} else {
						self.each(function() {
							if (_hasVal(this)) {
								this.value = val;
							} else {
								_setAttr(this, 'value', val);
							}
						});
						return self;
					}
				},
				css : function(key, val) {
					var self = this;
					if (key === undefined) {
						return _getCssList(self.attr('style'));
					}
					if (typeof key === 'object') {
						_each(key, function(k, v) {
							self.css(k, v);
						});
						return self;
					}
					if (val === undefined) {
						if (self.length < 1) {
							return '';
						}
						return self[0].style[_toCamel(key)]
								|| _computedCss(self[0], key) || '';
					}
					self.each(function() {
						this.style[_toCamel(key)] = val;
					});
					return self;
				},
				width : function(val) {
					var self = this;
					if (val === undefined) {
						if (self.length < 1) {
							return 0;
						}
						return self[0].offsetWidth;
					}
					return self.css('width', _addUnit(val));
				},
				height : function(val) {
					var self = this;
					if (val === undefined) {
						if (self.length < 1) {
							return 0;
						}
						return self[0].offsetHeight;
					}
					return self.css('height', _addUnit(val));
				},
				opacity : function(val) {
					this.each(function() {
						if (this.style.opacity === undefined) {
							this.style.filter = val == 1 ? ''
									: 'alpha(opacity=' + (val * 100) + ')';
						} else {
							this.style.opacity = val == 1 ? '' : val;
						}
					});
					return this;
				},
				data : function(key, val) {
					var self = this;
					key = 'kindeditor_data_' + key;
					if (val === undefined) {
						if (self.length < 1) {
							return null;
						}
						return self[0][key];
					}
					this.each(function() {
						this[key] = val;
					});
					return self;
				},
				pos : function() {
					var self = this, node = self[0], x = 0, y = 0;
					if (node) {
						if (node.getBoundingClientRect) {
							var box = node.getBoundingClientRect(), pos = _getScrollPos(self.doc);
							x = box.left + pos.x;
							y = box.top + pos.y;
						} else {
							while (node) {
								x += node.offsetLeft;
								y += node.offsetTop;
								node = node.offsetParent;
							}
						}
					}
					return {
						x : _round(x),
						y : _round(y)
					};
				},
				clone : function(bool) {
					if (this.length < 1) {
						return new KNode([]);
					}
					return new KNode(this[0].cloneNode(bool));
				},
				append : function(expr) {
					this.each(function() {
						if (this.appendChild) {
							this.appendChild(_get(expr));
						}
					});
					return this;
				},
				appendTo : function(expr) {
					this.each(function() {
						_get(expr).appendChild(this);
					});
					return this;
				},
				before : function(expr) {
					this.each(function() {
						this.parentNode.insertBefore(_get(expr), this);
					});
					return this;
				},
				after : function(expr) {
					this.each(function() {
						if (this.nextSibling) {
							this.parentNode.insertBefore(_get(expr),
									this.nextSibling);
						} else {
							this.parentNode.appendChild(_get(expr));
						}
					});
					return this;
				},
				replaceWith : function(expr) {
					var nodes = [];
					this.each(function(i, node) {
						_unbind(node);
						var newNode = _get(expr);
						node.parentNode.replaceChild(newNode, node);
						nodes.push(newNode);
					});
					return K(nodes);
				},
				empty : function() {
					var self = this;
					self.each(function(i, node) {
						var child = node.firstChild;
						while (child) {
							if (!node.parentNode) {
								return;
							}
							var next = child.nextSibling;
							child.parentNode.removeChild(child);
							child = next;
						}
					});
					return self;
				},
				remove : function(keepChilds) {
					var self = this;
					self.each(function(i, node) {
						if (!node.parentNode) {
							return;
						}
						_unbind(node);
						if (keepChilds) {
							var child = node.firstChild;
							while (child) {
								var next = child.nextSibling;
								node.parentNode.insertBefore(child, node);
								child = next;
							}
						}
						node.parentNode.removeChild(node);
						delete self[i];
					});
					self.length = 0;
					return self;
				},
				show : function(val) {
					var self = this;
					if (val === undefined) {
						val = self._originDisplay || '';
					}
					if (self.css('display') != 'none') {
						return self;
					}
					return self.css('display', val);
				},
				hide : function() {
					var self = this;
					if (self.length < 1) {
						return self;
					}
					self._originDisplay = self[0].style.display;
					return self.css('display', 'none');
				},
				outer : function() {
					var self = this;
					if (self.length < 1) {
						return '';
					}
					var div = self.doc.createElement('div'), html;
					div.appendChild(self[0].cloneNode(true));
					html = _formatHtml(div.innerHTML);
					div = null;
					return html;
				},
				isSingle : function() {
					return !!_SINGLE_TAG_MAP[this.name];
				},
				isInline : function() {
					return !!_INLINE_TAG_MAP[this.name];
				},
				isBlock : function() {
					return !!_BLOCK_TAG_MAP[this.name];
				},
				isStyle : function() {
					return !!_STYLE_TAG_MAP[this.name];
				},
				isControl : function() {
					return !!_CONTROL_TAG_MAP[this.name];
				},
				contains : function(otherNode) {
					if (this.length < 1) {
						return false;
					}
					return _contains(this[0], _get(otherNode));
				},
				parent : function() {
					if (this.length < 1) {
						return null;
					}
					var node = this[0].parentNode;
					return node ? new KNode(node) : null;
				},
				children : function() {
					if (this.length < 1) {
						return new KNode([]);
					}
					var list = [], child = this[0].firstChild;
					while (child) {
						if (child.nodeType != 3
								|| _trim(child.nodeValue) !== '') {
							list.push(child);
						}
						child = child.nextSibling;
					}
					return new KNode(list);
				},
				first : function() {
					var list = this.children();
					return list.length > 0 ? list.eq(0) : null;
				},
				last : function() {
					var list = this.children();
					return list.length > 0 ? list.eq(list.length - 1) : null;
				},
				index : function() {
					if (this.length < 1) {
						return -1;
					}
					var i = -1, sibling = this[0];
					while (sibling) {
						i++;
						sibling = sibling.previousSibling;
					}
					return i;
				},
				prev : function() {
					if (this.length < 1) {
						return null;
					}
					var node = this[0].previousSibling;
					return node ? new KNode(node) : null;
				},
				next : function() {
					if (this.length < 1) {
						return null;
					}
					var node = this[0].nextSibling;
					return node ? new KNode(node) : null;
				},
				scan : function(fn, order) {
					if (this.length < 1) {
						return;
					}
					order = (order === undefined) ? true : order;
					function walk(node) {
						var n = order ? node.firstChild : node.lastChild;
						while (n) {
							var next = order ? n.nextSibling
									: n.previousSibling;
							if (fn(n) === false) {
								return false;
							}
							if (walk(n) === false) {
								return false;
							}
							n = next;
						}
					}
					walk(this[0]);
					return this;
				}
			});
	_each(
			('blur,focus,focusin,focusout,load,resize,scroll,unload,click,dblclick,'
					+ 'mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,'
					+ 'change,select,submit,keydown,keypress,keyup,error,contextmenu')
					.split(','), function(i, type) {
				KNode.prototype[type] = function(fn) {
					return fn ? this.bind(type, fn) : this.fire(type);
				};
			});
	var _K = K;
	K = function(expr, root) {
		if (expr === undefined || expr === null) {
			return;
		}
		function newNode(node) {
			if (!node[0]) {
				node = [];
			}
			return new KNode(node);
		}
		if (typeof expr === 'string') {
			if (root) {
				root = _get(root);
			}
			var length = expr.length;
			if (expr.charAt(0) === '@') {
				expr = expr.substr(1);
			}
			if (expr.length !== length || /<.+>/.test(expr)) {
				var doc = root ? root.ownerDocument || root : document, div = doc
						.createElement('div'), list = [];
				div.innerHTML = '<img id="__kindeditor_temp_tag__" width="0" height="0" style="display:none;" />'
						+ expr;
				for (var i = 0, len = div.childNodes.length; i < len; i++) {
					var child = div.childNodes[i];
					if (child.id == '__kindeditor_temp_tag__') {
						continue;
					}
					list.push(child);
				}
				return newNode(list);
			}
			return newNode(_queryAll(expr, root));
		}
		if (expr && expr.constructor === KNode) {
			return expr;
		}
		if (expr.toArray) {
			expr = expr.toArray();
		}
		if (_isArray(expr)) {
			return newNode(expr);
		}
		return newNode(_toArray(arguments));
	};
	_each(_K, function(key, val) {
		K[key] = val;
	});
	K.NodeClass = KNode;
	window.KindEditor = K;
	var _START_TO_START = 0, _START_TO_END = 1, _END_TO_END = 2, _END_TO_START = 3, _BOOKMARK_ID = 0;
	function _updateCollapsed(range) {
		range.collapsed = (range.startContainer === range.endContainer && range.startOffset === range.endOffset);
		return range;
	}
	function _copyAndDelete(range, isCopy, isDelete) {
		var doc = range.doc, nodeList = [];
		function splitTextNode(node, startOffset, endOffset) {
			var length = node.nodeValue.length, centerNode;
			if (isCopy) {
				var cloneNode = node.cloneNode(true);
				if (startOffset > 0) {
					centerNode = cloneNode.splitText(startOffset);
				} else {
					centerNode = cloneNode;
				}
				if (endOffset < length) {
					centerNode.splitText(endOffset - startOffset);
				}
			}
			if (isDelete) {
				var center = node;
				if (startOffset > 0) {
					center = node.splitText(startOffset);
					range.setStart(node, startOffset);
				}
				if (endOffset < length) {
					var right = center.splitText(endOffset - startOffset);
					range.setEnd(right, 0);
				}
				nodeList.push(center);
			}
			return centerNode;
		}
		function removeNodes() {
			if (isDelete) {
				range.up().collapse(true);
			}
			for (var i = 0, len = nodeList.length; i < len; i++) {
				var node = nodeList[i];
				if (node.parentNode) {
					node.parentNode.removeChild(node);
				}
			}
		}
		var copyRange = range.cloneRange().down();
		var start = -1, incStart = -1, incEnd = -1, end = -1, ancestor = range
				.commonAncestor(), frag = doc.createDocumentFragment();
		if (ancestor.nodeType == 3) {
			var textNode = splitTextNode(ancestor, range.startOffset,
					range.endOffset);
			if (isCopy) {
				frag.appendChild(textNode);
			}
			removeNodes();
			return isCopy ? frag : range;
		}
		function extractNodes(parent, frag) {
			var node = parent.firstChild, nextNode;
			while (node) {
				var testRange = new KRange(doc).selectNode(node);
				start = testRange.compareBoundaryPoints(_START_TO_END, range);
				if (start >= 0 && incStart <= 0) {
					incStart = testRange.compareBoundaryPoints(_START_TO_START,
							range);
				}
				if (incStart >= 0 && incEnd <= 0) {
					incEnd = testRange
							.compareBoundaryPoints(_END_TO_END, range);
				}
				if (incEnd >= 0 && end <= 0) {
					end = testRange.compareBoundaryPoints(_END_TO_START, range);
				}
				if (end >= 0) {
					return false;
				}
				nextNode = node.nextSibling;
				if (start > 0) {
					if (node.nodeType == 1) {
						if (incStart >= 0 && incEnd <= 0) {
							if (isCopy) {
								frag.appendChild(node.cloneNode(true));
							}
							if (isDelete) {
								nodeList.push(node);
							}
						} else {
							var childFlag;
							if (isCopy) {
								childFlag = node.cloneNode(false);
								frag.appendChild(childFlag);
							}
							if (extractNodes(node, childFlag) === false) {
								return false;
							}
						}
					} else if (node.nodeType == 3) {
						var textNode;
						if (node == copyRange.startContainer) {
							textNode = splitTextNode(node,
									copyRange.startOffset,
									node.nodeValue.length);
						} else if (node == copyRange.endContainer) {
							textNode = splitTextNode(node, 0,
									copyRange.endOffset);
						} else {
							textNode = splitTextNode(node, 0,
									node.nodeValue.length);
						}
						if (isCopy) {
							try {
								frag.appendChild(textNode);
							} catch (e) {
							}
						}
					}
				}
				node = nextNode;
			}
		}
		extractNodes(ancestor, frag);
		if (isDelete) {
			range.up().collapse(true);
		}
		for (var i = 0, len = nodeList.length; i < len; i++) {
			var node = nodeList[i];
			if (node.parentNode) {
				node.parentNode.removeChild(node);
			}
		}
		return isCopy ? frag : range;
	}
	function _moveToElementText(range, el) {
		var node = el;
		while (node) {
			var knode = K(node);
			if (knode.name == 'marquee' || knode.name == 'select') {
				return;
			}
			node = node.parentNode;
		}
		try {
			range.moveToElementText(el);
		} catch (e) {
		}
	}
	function _getStartEnd(rng, isStart) {
		var doc = rng.parentElement().ownerDocument, pointRange = rng
				.duplicate();
		pointRange.collapse(isStart);
		var parent = pointRange.parentElement(), nodes = parent.childNodes;
		if (nodes.length === 0) {
			return {
				node : parent.parentNode,
				offset : K(parent).index()
			};
		}
		var startNode = doc, startPos = 0, cmp = -1;
		var testRange = rng.duplicate();
		_moveToElementText(testRange, parent);
		for (var i = 0, len = nodes.length; i < len; i++) {
			var node = nodes[i];
			cmp = testRange.compareEndPoints('StartToStart', pointRange);
			if (cmp === 0) {
				return {
					node : node.parentNode,
					offset : i
				};
			}
			if (node.nodeType == 1) {
				var nodeRange = rng.duplicate(), dummy, knode = K(node), newNode = node;
				if (knode.isControl()) {
					dummy = doc.createElement('span');
					knode.after(dummy);
					newNode = dummy;
					startPos += knode.text().replace(/\r\n|\n|\r/g, '').length;
				}
				_moveToElementText(nodeRange, newNode);
				testRange.setEndPoint('StartToEnd', nodeRange);
				if (cmp > 0) {
					startPos += nodeRange.text.replace(/\r\n|\n|\r/g, '').length;
				} else {
					startPos = 0;
				}
				if (dummy) {
					K(dummy).remove();
				}
			} else if (node.nodeType == 3) {
				testRange.moveStart('character', node.nodeValue.length);
				startPos += node.nodeValue.length;
			}
			if (cmp < 0) {
				startNode = node;
			}
		}
		if (cmp < 0 && startNode.nodeType == 1) {
			return {
				node : parent,
				offset : K(parent.lastChild).index() + 1
			};
		}
		if (cmp > 0) {
			while (startNode.nextSibling && startNode.nodeType == 1) {
				startNode = startNode.nextSibling;
			}
		}
		testRange = rng.duplicate();
		_moveToElementText(testRange, parent);
		testRange.setEndPoint('StartToEnd', pointRange);
		startPos -= testRange.text.replace(/\r\n|\n|\r/g, '').length;
		if (cmp > 0 && startNode.nodeType == 3) {
			var prevNode = startNode.previousSibling;
			while (prevNode && prevNode.nodeType == 3) {
				startPos -= prevNode.nodeValue.length;
				prevNode = prevNode.previousSibling;
			}
		}
		return {
			node : startNode,
			offset : startPos
		};
	}
	function _getEndRange(node, offset) {
		var doc = node.ownerDocument || node, range = doc.body
				.createTextRange();
		if (doc == node) {
			range.collapse(true);
			return range;
		}
		if (node.nodeType == 1 && node.childNodes.length > 0) {
			var children = node.childNodes, isStart, child;
			if (offset === 0) {
				child = children[0];
				isStart = true;
			} else {
				child = children[offset - 1];
				isStart = false;
			}
			if (!child) {
				return range;
			}
			if (K(child).name === 'head') {
				if (offset === 1) {
					isStart = true;
				}
				if (offset === 2) {
					isStart = false;
				}
				range.collapse(isStart);
				return range;
			}
			if (child.nodeType == 1) {
				var kchild = K(child), span;
				if (kchild.isControl()) {
					span = doc.createElement('span');
					if (isStart) {
						kchild.before(span);
					} else {
						kchild.after(span);
					}
					child = span;
				}
				_moveToElementText(range, child);
				range.collapse(isStart);
				if (span) {
					K(span).remove();
				}
				return range;
			}
			node = child;
			offset = isStart ? 0 : child.nodeValue.length;
		}
		var dummy = doc.createElement('span');
		K(node).before(dummy);
		_moveToElementText(range, dummy);
		range.moveStart('character', offset);
		K(dummy).remove();
		return range;
	}
	function _toRange(rng) {
		var doc, range;
		function tr2td(start) {
			if (K(start.node).name == 'tr') {
				start.node = start.node.cells[start.offset];
				start.offset = 0;
			}
		}
		if (_IERANGE) {
			if (rng.item) {
				doc = _getDoc(rng.item(0));
				range = new KRange(doc);
				range.selectNode(rng.item(0));
				return range;
			}
			doc = rng.parentElement().ownerDocument;
			var start = _getStartEnd(rng, true), end = _getStartEnd(rng, false);
			tr2td(start);
			tr2td(end);
			range = new KRange(doc);
			range.setStart(start.node, start.offset);
			range.setEnd(end.node, end.offset);
			return range;
		}
		var startContainer = rng.startContainer;
		doc = startContainer.ownerDocument || startContainer;
		range = new KRange(doc);
		range.setStart(startContainer, rng.startOffset);
		range.setEnd(rng.endContainer, rng.endOffset);
		return range;
	}
	function KRange(doc) {
		this.init(doc);
	}
	_extend(
			KRange,
			{
				init : function(doc) {
					var self = this;
					self.startContainer = doc;
					self.startOffset = 0;
					self.endContainer = doc;
					self.endOffset = 0;
					self.collapsed = true;
					self.doc = doc;
				},
				commonAncestor : function() {
					function getParents(node) {
						var parents = [];
						while (node) {
							parents.push(node);
							node = node.parentNode;
						}
						return parents;
					}
					var parentsA = getParents(this.startContainer), parentsB = getParents(this.endContainer), i = 0, lenA = parentsA.length, lenB = parentsB.length, parentA, parentB;
					while (++i) {
						parentA = parentsA[lenA - i];
						parentB = parentsB[lenB - i];
						if (!parentA || !parentB || parentA !== parentB) {
							break;
						}
					}
					return parentsA[lenA - i + 1];
				},
				setStart : function(node, offset) {
					var self = this, doc = self.doc;
					self.startContainer = node;
					self.startOffset = offset;
					if (self.endContainer === doc) {
						self.endContainer = node;
						self.endOffset = offset;
					}
					return _updateCollapsed(this);
				},
				setEnd : function(node, offset) {
					var self = this, doc = self.doc;
					self.endContainer = node;
					self.endOffset = offset;
					if (self.startContainer === doc) {
						self.startContainer = node;
						self.startOffset = offset;
					}
					return _updateCollapsed(this);
				},
				setStartBefore : function(node) {
					return this.setStart(node.parentNode || this.doc, K(node)
							.index());
				},
				setStartAfter : function(node) {
					return this.setStart(node.parentNode || this.doc, K(node)
							.index() + 1);
				},
				setEndBefore : function(node) {
					return this.setEnd(node.parentNode || this.doc, K(node)
							.index());
				},
				setEndAfter : function(node) {
					return this.setEnd(node.parentNode || this.doc, K(node)
							.index() + 1);
				},
				selectNode : function(node) {
					return this.setStartBefore(node).setEndAfter(node);
				},
				selectNodeContents : function(node) {
					var knode = K(node);
					if (knode.type == 3 || knode.isSingle()) {
						return this.selectNode(node);
					}
					var children = knode.children();
					if (children.length > 0) {
						return this.setStartBefore(children[0]).setEndAfter(
								children[children.length - 1]);
					}
					return this.setStart(node, 0).setEnd(node, 0);
				},
				collapse : function(toStart) {
					if (toStart) {
						return this.setEnd(this.startContainer,
								this.startOffset);
					}
					return this.setStart(this.endContainer, this.endOffset);
				},
				compareBoundaryPoints : function(how, range) {
					var rangeA = this.get(), rangeB = range.get();
					if (_IERANGE) {
						var arr = {};
						arr[_START_TO_START] = 'StartToStart';
						arr[_START_TO_END] = 'EndToStart';
						arr[_END_TO_END] = 'EndToEnd';
						arr[_END_TO_START] = 'StartToEnd';
						var cmp = rangeA.compareEndPoints(arr[how], rangeB);
						if (cmp !== 0) {
							return cmp;
						}
						var nodeA, nodeB, nodeC, posA, posB;
						if (how === _START_TO_START || how === _END_TO_START) {
							nodeA = this.startContainer;
							posA = this.startOffset;
						}
						if (how === _START_TO_END || how === _END_TO_END) {
							nodeA = this.endContainer;
							posA = this.endOffset;
						}
						if (how === _START_TO_START || how === _START_TO_END) {
							nodeB = range.startContainer;
							posB = range.startOffset;
						}
						if (how === _END_TO_END || how === _END_TO_START) {
							nodeB = range.endContainer;
							posB = range.endOffset;
						}
						if (nodeA === nodeB) {
							var diff = posA - posB;
							return diff > 0 ? 1 : (diff < 0 ? -1 : 0);
						}
						nodeC = nodeB;
						while (nodeC && nodeC.parentNode !== nodeA) {
							nodeC = nodeC.parentNode;
						}
						if (nodeC) {
							return K(nodeC).index() >= posA ? -1 : 1;
						}
						nodeC = nodeA;
						while (nodeC && nodeC.parentNode !== nodeB) {
							nodeC = nodeC.parentNode;
						}
						if (nodeC) {
							return K(nodeC).index() >= posB ? 1 : -1;
						}
						nodeC = K(nodeB).next();
						if (nodeC && nodeC.contains(nodeA)) {
							return 1;
						}
						nodeC = K(nodeA).next();
						if (nodeC && nodeC.contains(nodeB)) {
							return -1;
						}
					} else {
						return rangeA.compareBoundaryPoints(how, rangeB);
					}
				},
				cloneRange : function() {
					return new KRange(this.doc).setStart(this.startContainer,
							this.startOffset).setEnd(this.endContainer,
							this.endOffset);
				},
				toString : function() {
					var rng = this.get(), str = _IERANGE ? rng.text : rng
							.toString();
					return str.replace(/\r\n|\n|\r/g, '');
				},
				cloneContents : function() {
					return _copyAndDelete(this, true, false);
				},
				deleteContents : function() {
					return _copyAndDelete(this, false, true);
				},
				extractContents : function() {
					return _copyAndDelete(this, true, true);
				},
				insertNode : function(node) {
					var self = this, sc = self.startContainer, so = self.startOffset, ec = self.endContainer, eo = self.endOffset, firstChild, lastChild, c, nodeCount = 1;
					if (node.nodeName.toLowerCase() === '#document-fragment') {
						firstChild = node.firstChild;
						lastChild = node.lastChild;
						nodeCount = node.childNodes.length;
					}
					if (sc.nodeType == 1) {
						c = sc.childNodes[so];
						if (c) {
							sc.insertBefore(node, c);
							if (sc === ec) {
								eo += nodeCount;
							}
						} else {
							sc.appendChild(node);
						}
					} else if (sc.nodeType == 3) {
						if (so === 0) {
							sc.parentNode.insertBefore(node, sc);
							if (sc.parentNode === ec) {
								eo += nodeCount;
							}
						} else if (so >= sc.nodeValue.length) {
							if (sc.nextSibling) {
								sc.parentNode
										.insertBefore(node, sc.nextSibling);
							} else {
								sc.parentNode.appendChild(node);
							}
						} else {
							if (so > 0) {
								c = sc.splitText(so);
							} else {
								c = sc;
							}
							sc.parentNode.insertBefore(node, c);
							if (sc === ec) {
								ec = c;
								eo -= so;
							}
						}
					}
					if (firstChild) {
						self.setStartBefore(firstChild).setEndAfter(lastChild);
					} else {
						self.selectNode(node);
					}
					if (self.compareBoundaryPoints(_END_TO_END, self
							.cloneRange().setEnd(ec, eo)) >= 1) {
						return self;
					}
					return self.setEnd(ec, eo);
				},
				surroundContents : function(node) {
					node.appendChild(this.extractContents());
					return this.insertNode(node).selectNode(node);
				},
				isControl : function() {
					var self = this, sc = self.startContainer, so = self.startOffset, ec = self.endContainer, eo = self.endOffset, rng;
					return sc.nodeType == 1 && sc === ec && so + 1 === eo
							&& K(sc.childNodes[so]).isControl();
				},
				get : function(hasControlRange) {
					var self = this, doc = self.doc, node, rng;
					if (!_IERANGE) {
						rng = doc.createRange();
						try {
							rng.setStart(self.startContainer, self.startOffset);
							rng.setEnd(self.endContainer, self.endOffset);
						} catch (e) {
						}
						return rng;
					}
					if (hasControlRange && self.isControl()) {
						rng = doc.body.createControlRange();
						rng
								.addElement(self.startContainer.childNodes[self.startOffset]);
						return rng;
					}
					var range = self.cloneRange().down();
					rng = doc.body.createTextRange();
					rng.setEndPoint('StartToStart', _getEndRange(
							range.startContainer, range.startOffset));
					rng.setEndPoint('EndToStart', _getEndRange(
							range.endContainer, range.endOffset));
					return rng;
				},
				html : function() {
					return K(this.cloneContents()).outer();
				},
				down : function() {
					var self = this;
					function downPos(node, pos, isStart) {
						if (node.nodeType != 1) {
							return;
						}
						var children = K(node).children();
						if (children.length === 0) {
							return;
						}
						var left, right, child, offset;
						if (pos > 0) {
							left = children.eq(pos - 1);
						}
						if (pos < children.length) {
							right = children.eq(pos);
						}
						if (left && left.type == 3) {
							child = left[0];
							offset = child.nodeValue.length;
						}
						if (right && right.type == 3) {
							child = right[0];
							offset = 0;
						}
						if (!child) {
							return;
						}
						if (isStart) {
							self.setStart(child, offset);
						} else {
							self.setEnd(child, offset);
						}
					}
					downPos(self.startContainer, self.startOffset, true);
					downPos(self.endContainer, self.endOffset, false);
					return self;
				},
				up : function() {
					var self = this;
					function upPos(node, pos, isStart) {
						if (node.nodeType != 3) {
							return;
						}
						if (pos === 0) {
							if (isStart) {
								self.setStartBefore(node);
							} else {
								self.setEndBefore(node);
							}
						} else if (pos == node.nodeValue.length) {
							if (isStart) {
								self.setStartAfter(node);
							} else {
								self.setEndAfter(node);
							}
						}
					}
					upPos(self.startContainer, self.startOffset, true);
					upPos(self.endContainer, self.endOffset, false);
					return self;
				},
				enlarge : function(toBlock) {
					var self = this;
					self.up();
					function enlargePos(node, pos, isStart) {
						var knode = K(node), parent;
						if (knode.type == 3 || _NOSPLIT_TAG_MAP[knode.name]
								|| !toBlock && knode.isBlock()) {
							return;
						}
						if (pos === 0) {
							while (!knode.prev()) {
								parent = knode.parent();
								if (!parent || _NOSPLIT_TAG_MAP[parent.name]
										|| !toBlock && parent.isBlock()) {
									break;
								}
								knode = parent;
							}
							if (isStart) {
								self.setStartBefore(knode[0]);
							} else {
								self.setEndBefore(knode[0]);
							}
						} else if (pos == knode.children().length) {
							while (!knode.next()) {
								parent = knode.parent();
								if (!parent || _NOSPLIT_TAG_MAP[parent.name]
										|| !toBlock && parent.isBlock()) {
									break;
								}
								knode = parent;
							}
							if (isStart) {
								self.setStartAfter(knode[0]);
							} else {
								self.setEndAfter(knode[0]);
							}
						}
					}
					enlargePos(self.startContainer, self.startOffset, true);
					enlargePos(self.endContainer, self.endOffset, false);
					return self;
				},
				shrink : function() {
					var self = this, child, collapsed = self.collapsed;
					while (self.startContainer.nodeType == 1
							&& (child = self.startContainer.childNodes[self.startOffset])
							&& child.nodeType == 1 && !K(child).isSingle()) {
						self.setStart(child, 0);
					}
					if (collapsed) {
						return self.collapse(collapsed);
					}
					while (self.endContainer.nodeType == 1
							&& self.endOffset > 0
							&& (child = self.endContainer.childNodes[self.endOffset - 1])
							&& child.nodeType == 1 && !K(child).isSingle()) {
						self.setEnd(child, child.childNodes.length);
					}
					return self;
				},
				createBookmark : function(serialize) {
					var self = this, doc = self.doc, endNode, startNode = K(
							'<span style="display:none;"></span>', doc)[0];
					startNode.id = '__kindeditor_bookmark_start_'
							+ (_BOOKMARK_ID++) + '__';
					if (!self.collapsed) {
						endNode = startNode.cloneNode(true);
						endNode.id = '__kindeditor_bookmark_end_'
								+ (_BOOKMARK_ID++) + '__';
					}
					if (endNode) {
						self.cloneRange().collapse(false).insertNode(endNode)
								.setEndBefore(endNode);
					}
					self.insertNode(startNode).setStartAfter(startNode);
					return {
						start : serialize ? '#' + startNode.id : startNode,
						end : endNode ? (serialize ? '#' + endNode.id : endNode)
								: null
					};
				},
				moveToBookmark : function(bookmark) {
					var self = this, doc = self.doc, start = K(bookmark.start,
							doc), end = bookmark.end ? K(bookmark.end, doc)
							: null;
					if (!start || start.length < 1) {
						return self;
					}
					self.setStartBefore(start[0]);
					start.remove();
					if (end && end.length > 0) {
						self.setEndBefore(end[0]);
						end.remove();
					} else {
						self.collapse(true);
					}
					return self;
				},
				dump : function() {
					console.log('--------------------');
					console
							.log(
									this.startContainer.nodeType == 3 ? this.startContainer.nodeValue
											: this.startContainer,
									this.startOffset);
					console
							.log(
									this.endContainer.nodeType == 3 ? this.endContainer.nodeValue
											: this.endContainer, this.endOffset);
				}
			});
	function _range(mixed) {
		if (!mixed.nodeName) {
			return mixed.constructor === KRange ? mixed : _toRange(mixed);
		}
		return new KRange(mixed);
	}
	K.RangeClass = KRange;
	K.range = _range;
	K.START_TO_START = _START_TO_START;
	K.START_TO_END = _START_TO_END;
	K.END_TO_END = _END_TO_END;
	K.END_TO_START = _END_TO_START;
	function _nativeCommand(doc, key, val) {
		try {
			doc.execCommand(key, false, val);
		} catch (e) {
		}
	}
	function _nativeCommandValue(doc, key) {
		var val = '';
		try {
			val = doc.queryCommandValue(key);
		} catch (e) {
		}
		if (typeof val !== 'string') {
			val = '';
		}
		return val;
	}
	function _getSel(doc) {
		var win = _getWin(doc);
		return _IERANGE ? doc.selection : win.getSelection();
	}
	function _getRng(doc) {
		var sel = _getSel(doc), rng;
		try {
			if (sel.rangeCount > 0) {
				rng = sel.getRangeAt(0);
			} else {
				rng = sel.createRange();
			}
		} catch (e) {
		}
		if (_IERANGE
				&& (!rng || (!rng.item && rng.parentElement().ownerDocument !== doc))) {
			return null;
		}
		return rng;
	}
	function _singleKeyMap(map) {
		var newMap = {}, arr, v;
		_each(map, function(key, val) {
			arr = key.split(',');
			for (var i = 0, len = arr.length; i < len; i++) {
				v = arr[i];
				newMap[v] = val;
			}
		});
		return newMap;
	}
	function _hasAttrOrCss(knode, map) {
		return _hasAttrOrCssByKey(knode, map, '*')
				|| _hasAttrOrCssByKey(knode, map);
	}
	function _hasAttrOrCssByKey(knode, map, mapKey) {
		mapKey = mapKey || knode.name;
		if (knode.type !== 1) {
			return false;
		}
		var newMap = _singleKeyMap(map);
		if (!newMap[mapKey]) {
			return false;
		}
		var arr = newMap[mapKey].split(',');
		for (var i = 0, len = arr.length; i < len; i++) {
			var key = arr[i];
			if (key === '*') {
				return true;
			}
			var match = /^(\.?)([^=]+)(?:=([^=]*))?$/.exec(key);
			var method = match[1] ? 'css' : 'attr';
			key = match[2];
			var val = match[3] || '';
			if (val === '' && knode[method](key) !== '') {
				return true;
			}
			if (val !== '' && knode[method](key) === val) {
				return true;
			}
		}
		return false;
	}
	function _removeAttrOrCss(knode, map) {
		if (knode.type != 1) {
			return;
		}
		_removeAttrOrCssByKey(knode, map, '*');
		_removeAttrOrCssByKey(knode, map);
	}
	function _removeAttrOrCssByKey(knode, map, mapKey) {
		mapKey = mapKey || knode.name;
		if (knode.type !== 1) {
			return;
		}
		var newMap = _singleKeyMap(map);
		if (!newMap[mapKey]) {
			return;
		}
		var arr = newMap[mapKey].split(','), allFlag = false;
		for (var i = 0, len = arr.length; i < len; i++) {
			var key = arr[i];
			if (key === '*') {
				allFlag = true;
				break;
			}
			var match = /^(\.?)([^=]+)(?:=([^=]*))?$/.exec(key);
			key = match[2];
			if (match[1]) {
				key = _toCamel(key);
				if (knode[0].style[key]) {
					knode[0].style[key] = '';
				}
			} else {
				knode.removeAttr(key);
			}
		}
		if (allFlag) {
			knode.remove(true);
		}
	}
	function _getInnerNode(knode) {
		var inner = knode;
		while (inner.first()) {
			inner = inner.first();
		}
		return inner;
	}
	function _isEmptyNode(knode) {
		if (knode.type != 1 || knode.isSingle()) {
			return false;
		}
		return knode.html().replace(/<[^>]+>/g, '') === '';
	}
	function _mergeWrapper(a, b) {
		a = a.clone(true);
		var lastA = _getInnerNode(a), childA = a, merged = false;
		while (b) {
			while (childA) {
				if (childA.name === b.name) {
					_mergeAttrs(childA, b.attr(), b.css());
					merged = true;
				}
				childA = childA.first();
			}
			if (!merged) {
				lastA.append(b.clone(false));
			}
			merged = false;
			b = b.first();
		}
		return a;
	}
	function _wrapNode(knode, wrapper) {
		wrapper = wrapper.clone(true);
		if (knode.type == 3) {
			_getInnerNode(wrapper).append(knode.clone(false));
			knode.replaceWith(wrapper);
			return wrapper;
		}
		var nodeWrapper = knode, child;
		while ((child = knode.first()) && child.children().length == 1) {
			knode = child;
		}
		child = knode.first();
		var frag = knode.doc.createDocumentFragment();
		while (child) {
			frag.appendChild(child[0]);
			child = child.next();
		}
		wrapper = _mergeWrapper(nodeWrapper, wrapper);
		if (frag.firstChild) {
			_getInnerNode(wrapper).append(frag);
		}
		nodeWrapper.replaceWith(wrapper);
		return wrapper;
	}
	function _mergeAttrs(knode, attrs, styles) {
		_each(attrs, function(key, val) {
			if (key !== 'style') {
				knode.attr(key, val);
			}
		});
		_each(styles, function(key, val) {
			knode.css(key, val);
		});
	}
	function _inPreElement(knode) {
		while (knode && knode.name != 'body') {
			if (_PRE_TAG_MAP[knode.name] || knode.name == 'div'
					&& knode.hasClass('ke-script')) {
				return true;
			}
			knode = knode.parent();
		}
		return false;
	}
	function KCmd(range) {
		this.init(range);
	}
	_extend(
			KCmd,
			{
				init : function(range) {
					var self = this, doc = range.doc;
					self.doc = doc;
					self.win = _getWin(doc);
					self.sel = _getSel(doc);
					self.range = range;
				},
				selection : function(forceReset) {
					var self = this, doc = self.doc, rng = _getRng(doc);
					self.sel = _getSel(doc);
					if (rng) {
						self.range = _range(rng);
						if (K(self.range.startContainer).name == 'html') {
							self.range.selectNodeContents(doc.body).collapse(
									false);
						}
						return self;
					}
					if (forceReset) {
						self.range.selectNodeContents(doc.body).collapse(false);
					}
					return self;
				},
				select : function(hasDummy) {
					hasDummy = _undef(hasDummy, true);
					var self = this, sel = self.sel, range = self.range
							.cloneRange().shrink(), sc = range.startContainer, so = range.startOffset, ec = range.endContainer, eo = range.endOffset, doc = _getDoc(sc), win = self.win, rng, hasU200b = false;
					if (hasDummy && sc.nodeType == 1 && range.collapsed) {
						if (_IERANGE) {
							var dummy = K('<span>&nbsp;</span>', doc);
							range.insertNode(dummy[0]);
							rng = doc.body.createTextRange();
							try {
								rng.moveToElementText(dummy[0]);
							} catch (ex) {
							}
							rng.collapse(false);
							rng.select();
							dummy.remove();
							win.focus();
							return self;
						}
						if (_WEBKIT) {
							var children = sc.childNodes;
							if (K(sc).isInline() || so > 0
									&& K(children[so - 1]).isInline()
									|| children[so]
									&& K(children[so]).isInline()) {
								range.insertNode(doc.createTextNode('\u200B'));
								hasU200b = true;
							}
						}
					}
					if (_IERANGE) {
						try {
							rng = range.get(true);
							rng.select();
						} catch (e) {
						}
					} else {
						if (hasU200b) {
							range.collapse(false);
						}
						rng = range.get(true);
						sel.removeAllRanges();
						sel.addRange(rng);
						if (doc !== document) {
							var pos = K(rng.endContainer).pos();
							win.scrollTo(pos.x, pos.y);
						}
					}
					win.focus();
					return self;
				},
				wrap : function(val) {
					var self = this, doc = self.doc, range = self.range, wrapper;
					wrapper = K(val, doc);
					if (range.collapsed) {
						range.shrink();
						range.insertNode(wrapper[0]).selectNodeContents(
								wrapper[0]);
						return self;
					}
					if (wrapper.isBlock()) {
						var copyWrapper = wrapper.clone(true), child = copyWrapper;
						while (child.first()) {
							child = child.first();
						}
						child.append(range.extractContents());
						range.insertNode(copyWrapper[0]).selectNode(
								copyWrapper[0]);
						return self;
					}
					range.enlarge();
					var bookmark = range.createBookmark(), ancestor = range
							.commonAncestor(), isStart = false;
					K(ancestor)
							.scan(
									function(node) {
										if (!isStart && node == bookmark.start) {
											isStart = true;
											return;
										}
										if (isStart) {
											if (node == bookmark.end) {
												return false;
											}
											var knode = K(node);
											if (_inPreElement(knode)) {
												return;
											}
											if (knode.type == 3
													&& _trim(node.nodeValue).length > 0) {
												var parent;
												while ((parent = knode.parent())
														&& parent.isStyle()
														&& parent.children().length == 1) {
													knode = parent;
												}
												_wrapNode(knode, wrapper);
											}
										}
									});
					range.moveToBookmark(bookmark);
					return self;
				},
				split : function(isStart, map) {
					var range = this.range, doc = range.doc;
					var tempRange = range.cloneRange().collapse(isStart);
					var node = tempRange.startContainer, pos = tempRange.startOffset, parent = node.nodeType == 3 ? node.parentNode
							: node, needSplit = false, knode;
					while (parent && parent.parentNode) {
						knode = K(parent);
						if (map) {
							if (!knode.isStyle()) {
								break;
							}
							if (!_hasAttrOrCss(knode, map)) {
								break;
							}
						} else {
							if (_NOSPLIT_TAG_MAP[knode.name]) {
								break;
							}
						}
						needSplit = true;
						parent = parent.parentNode;
					}
					if (needSplit) {
						var dummy = doc.createElement('span');
						range.cloneRange().collapse(!isStart).insertNode(dummy);
						if (isStart) {
							tempRange.setStartBefore(parent.firstChild).setEnd(
									node, pos);
						} else {
							tempRange.setStart(node, pos).setEndAfter(
									parent.lastChild);
						}
						var frag = tempRange.extractContents(), first = frag.firstChild, last = frag.lastChild;
						if (isStart) {
							tempRange.insertNode(frag);
							range.setStartAfter(last).setEndBefore(dummy);
						} else {
							parent.appendChild(frag);
							range.setStartBefore(dummy).setEndBefore(first);
						}
						var dummyParent = dummy.parentNode;
						if (dummyParent == range.endContainer) {
							var prev = K(dummy).prev(), next = K(dummy).next();
							if (prev && next && prev.type == 3
									&& next.type == 3) {
								range.setEnd(prev[0], prev[0].nodeValue.length);
							} else if (!isStart) {
								range.setEnd(range.endContainer,
										range.endOffset - 1);
							}
						}
						dummyParent.removeChild(dummy);
					}
					return this;
				},
				remove : function(map) {
					var self = this, doc = self.doc, range = self.range;
					range.enlarge();
					if (range.startOffset === 0) {
						var ksc = K(range.startContainer), parent;
						while ((parent = ksc.parent()) && parent.isStyle()
								&& parent.children().length == 1) {
							ksc = parent;
						}
						range.setStart(ksc[0], 0);
						ksc = K(range.startContainer);
						if (ksc.isBlock()) {
							_removeAttrOrCss(ksc, map);
						}
						var kscp = ksc.parent();
						if (kscp && kscp.isBlock()) {
							_removeAttrOrCss(kscp, map);
						}
					}
					var sc, so;
					if (range.collapsed) {
						self.split(true, map);
						sc = range.startContainer;
						so = range.startOffset;
						if (so > 0) {
							var sb = K(sc.childNodes[so - 1]);
							if (sb && _isEmptyNode(sb)) {
								sb.remove();
								range.setStart(sc, so - 1);
							}
						}
						var sa = K(sc.childNodes[so]);
						if (sa && _isEmptyNode(sa)) {
							sa.remove();
						}
						if (_isEmptyNode(sc)) {
							range.startBefore(sc);
							sc.remove();
						}
						range.collapse(true);
						return self;
					}
					self.split(true, map);
					self.split(false, map);
					var startDummy = doc.createElement('span'), endDummy = doc
							.createElement('span');
					range.cloneRange().collapse(false).insertNode(endDummy);
					range.cloneRange().collapse(true).insertNode(startDummy);
					var nodeList = [], cmpStart = false;
					K(range.commonAncestor()).scan(function(node) {
						if (!cmpStart && node == startDummy) {
							cmpStart = true;
							return;
						}
						if (node == endDummy) {
							return false;
						}
						if (cmpStart) {
							nodeList.push(node);
						}
					});
					K(startDummy).remove();
					K(endDummy).remove();
					sc = range.startContainer;
					so = range.startOffset;
					var ec = range.endContainer, eo = range.endOffset;
					if (so > 0) {
						var startBefore = K(sc.childNodes[so - 1]);
						if (startBefore && _isEmptyNode(startBefore)) {
							startBefore.remove();
							range.setStart(sc, so - 1);
							if (sc == ec) {
								range.setEnd(ec, eo - 1);
							}
						}
						var startAfter = K(sc.childNodes[so]);
						if (startAfter && _isEmptyNode(startAfter)) {
							startAfter.remove();
							if (sc == ec) {
								range.setEnd(ec, eo - 1);
							}
						}
					}
					var endAfter = K(ec.childNodes[range.endOffset]);
					if (endAfter && _isEmptyNode(endAfter)) {
						endAfter.remove();
					}
					var bookmark = range.createBookmark(true);
					_each(nodeList, function(i, node) {
						_removeAttrOrCss(K(node), map);
					});
					range.moveToBookmark(bookmark);
					return self;
				},
				commonNode : function(map) {
					var range = this.range;
					var ec = range.endContainer, eo = range.endOffset, node = (ec.nodeType == 3 || eo === 0) ? ec
							: ec.childNodes[eo - 1];
					function find(node) {
						var child = node, parent = node;
						while (parent) {
							if (_hasAttrOrCss(K(parent), map)) {
								return K(parent);
							}
							parent = parent.parentNode;
						}
						while (child && (child = child.lastChild)) {
							if (_hasAttrOrCss(K(child), map)) {
								return K(child);
							}
						}
						return null;
					}
					var cNode = find(node);
					if (cNode) {
						return cNode;
					}
					if (node.nodeType == 1 || (ec.nodeType == 3 && eo === 0)) {
						var prev = K(node).prev();
						if (prev) {
							return find(prev);
						}
					}
					return null;
				},
				commonAncestor : function(tagName) {
					var range = this.range, sc = range.startContainer, so = range.startOffset, ec = range.endContainer, eo = range.endOffset, startNode = (sc.nodeType == 3 || so === 0) ? sc
							: sc.childNodes[so - 1], endNode = (ec.nodeType == 3 || eo === 0) ? ec
							: ec.childNodes[eo - 1];
					function find(node) {
						while (node) {
							if (node.nodeType == 1) {
								if (node.tagName.toLowerCase() === tagName) {
									return node;
								}
							}
							node = node.parentNode;
						}
						return null;
					}
					var start = find(startNode), end = find(endNode);
					if (start && end && start === end) {
						return K(start);
					}
					return null;
				},
				state : function(key) {
					var self = this, doc = self.doc, bool = false;
					try {
						bool = doc.queryCommandState(key);
					} catch (e) {
					}
					return bool;
				},
				val : function(key) {
					var self = this, doc = self.doc, range = self.range;
					function lc(val) {
						return val.toLowerCase();
					}
					key = lc(key);
					var val = '', knode;
					if (key === 'fontfamily' || key === 'fontname') {
						val = _nativeCommandValue(doc, 'fontname');
						val = val.replace(/['"]/g, '');
						return lc(val);
					}
					if (key === 'formatblock') {
						val = _nativeCommandValue(doc, key);
						if (val === '') {
							knode = self.commonNode({
								'h1,h2,h3,h4,h5,h6,p,div,pre,address' : '*'
							});
							if (knode) {
								val = knode.name;
							}
						}
						if (val === 'Normal') {
							val = 'p';
						}
						return lc(val);
					}
					if (key === 'fontsize') {
						knode = self.commonNode({
							'*' : '.font-size'
						});
						if (knode) {
							val = knode.css('font-size');
						}
						return lc(val);
					}
					if (key === 'forecolor') {
						knode = self.commonNode({
							'*' : '.color'
						});
						if (knode) {
							val = knode.css('color');
						}
						val = _toHex(val);
						if (val === '') {
							val = 'default';
						}
						return lc(val);
					}
					if (key === 'hilitecolor') {
						knode = self.commonNode({
							'*' : '.background-color'
						});
						if (knode) {
							val = knode.css('background-color');
						}
						val = _toHex(val);
						if (val === '') {
							val = 'default';
						}
						return lc(val);
					}
					return val;
				},
				toggle : function(wrapper, map) {
					var self = this;
					if (self.commonNode(map)) {
						self.remove(map);
					} else {
						self.wrap(wrapper);
					}
					return self.select();
				},
				bold : function() {
					return this.toggle('<strong></strong>', {
						span : '.font-weight=bold',
						strong : '*',
						b : '*'
					});
				},
				italic : function() {
					return this.toggle('<em></em>', {
						span : '.font-style=italic',
						em : '*',
						i : '*'
					});
				},
				underline : function() {
					return this.toggle('<u></u>', {
						span : '.text-decoration=underline',
						u : '*'
					});
				},
				strikethrough : function() {
					return this.toggle('<s></s>', {
						span : '.text-decoration=line-through',
						s : '*'
					});
				},
				forecolor : function(val) {
					return this
							.wrap('<span style="color:' + val + ';"></span>')
							.select();
				},
				hilitecolor : function(val) {
					return this.wrap(
							'<span style="background-color:' + val
									+ ';"></span>').select();
				},
				fontsize : function(val) {
					return this.wrap(
							'<span style="font-size:' + val + ';"></span>')
							.select();
				},
				fontname : function(val) {
					return this.fontfamily(val);
				},
				fontfamily : function(val) {
					return this.wrap(
							'<span style="font-family:' + val + ';"></span>')
							.select();
				},
				removeformat : function() {
					var map = {
						'*' : '.font-weight,.font-style,.text-decoration,.color,.background-color,.font-size,.font-family,.text-indent'
					}, tags = _STYLE_TAG_MAP;
					_each(tags, function(key, val) {
						map[key] = '*';
					});
					this.remove(map);
					return this.select();
				},
				inserthtml : function(val, quickMode) {
					var self = this, range = self.range;
					if (val === '') {
						return self;
					}
					function pasteHtml(range, val) {
						val = '<img id="__kindeditor_temp_tag__" width="0" height="0" style="display:none;" />'
								+ val;
						var rng = range.get();
						if (rng.item) {
							rng.item(0).outerHTML = val;
						} else {
							rng.pasteHTML(val);
						}
						var temp = range.doc
								.getElementById('__kindeditor_temp_tag__');
						temp.parentNode.removeChild(temp);
						var newRange = _toRange(rng);
						range.setEnd(newRange.endContainer, newRange.endOffset);
						range.collapse(false);
						self.select(false);
					}
					function insertHtml(range, val) {
						var doc = range.doc, frag = doc
								.createDocumentFragment();
						K('@' + val, doc).each(function() {
							frag.appendChild(this);
						});
						range.deleteContents();
						range.insertNode(frag);
						range.collapse(false);
						self.select(false);
					}
					if (_IERANGE && quickMode) {
						try {
							pasteHtml(range, val);
						} catch (e) {
							insertHtml(range, val);
						}
						return self;
					}
					insertHtml(range, val);
					return self;
				},
				hr : function() {
					return this.inserthtml('<hr />');
				},
				print : function() {
					this.win.print();
					return this;
				},
				insertimage : function(url, title, width, height, border, align) {
					title = _undef(title, '');
					border = _undef(border, 0);
					var html = '<img src="' + _escape(url) + '" data-ke-src="'
							+ _escape(url) + '" ';
					if (width) {
						html += 'width="' + _escape(width) + '" ';
					}
					if (height) {
						html += 'height="' + _escape(height) + '" ';
					}
					if (title) {
						html += 'title="' + _escape(title) + '" ';
					}
					if (align) {
						html += 'align="' + _escape(align) + '" ';
					}
					html += 'alt="' + _escape(title) + '" ';
					html += '/>';
					return this.inserthtml(html);
				},
				createlink : function(url, type) {
					var self = this, doc = self.doc, range = self.range;
					self.select();
					var a = self.commonNode({
						a : '*'
					});
					if (a && !range.isControl()) {
						range.selectNode(a.get());
						self.select();
					}
					var html = '<a href="' + _escape(url) + '" data-ke-src="'
							+ _escape(url) + '" ';
					if (type) {
						html += ' target="' + _escape(type) + '"';
					}
					if (range.collapsed) {
						html += '>' + _escape(url) + '</a>';
						return self.inserthtml(html);
					}
					if (range.isControl()) {
						var node = K(range.startContainer.childNodes[range.startOffset]);
						html += '></a>';
						node.after(K(html, doc));
						node.next().append(node);
						range.selectNode(node[0]);
						return self.select();
					}
					function setAttr(node, url, type) {
						K(node).attr('href', url).attr('data-ke-src', url);
						if (type) {
							K(node).attr('target', type);
						} else {
							K(node).removeAttr('target');
						}
					}
					var sc = range.startContainer, so = range.startOffset, ec = range.endContainer, eo = range.endOffset;
					if (sc.nodeType == 1 && sc === ec && so + 1 === eo) {
						var child = sc.childNodes[so];
						if (child.nodeName.toLowerCase() == 'a') {
							setAttr(child, url, type);
							return self;
						}
					}
					_nativeCommand(doc, 'createlink', '__kindeditor_temp_url__');
					K('a[href="__kindeditor_temp_url__"]', doc).each(
							function() {
								setAttr(this, url, type);
							});
					return self;
				},
				unlink : function() {
					var self = this, doc = self.doc, range = self.range;
					self.select();
					if (range.collapsed) {
						var a = self.commonNode({
							a : '*'
						});
						if (a) {
							range.selectNode(a.get());
							self.select();
						}
						_nativeCommand(doc, 'unlink', null);
						if (_WEBKIT && K(range.startContainer).name === 'img') {
							var parent = K(range.startContainer).parent();
							if (parent.name === 'a') {
								parent.remove(true);
							}
						}
					} else {
						_nativeCommand(doc, 'unlink', null);
					}
					return self;
				}
			});
	_each(
			('formatblock,selectall,justifyleft,justifycenter,justifyright,justifyfull,insertorderedlist,'
					+ 'insertunorderedlist,indent,outdent,subscript,superscript')
					.split(','), function(i, name) {
				KCmd.prototype[name] = function(val) {
					var self = this;
					self.select();
					_nativeCommand(self.doc, name, val);
					if (_IERANGE
							&& _inArray(name,
									'justifyleft,justifycenter,justifyright,justifyfull'
											.split(',')) >= 0) {
						self.selection();
					}
					if (!_IERANGE
							|| _inArray(name,
									'formatblock,selectall,insertorderedlist,insertunorderedlist'
											.split(',')) >= 0) {
						self.selection();
					}
					return self;
				};
			});
	_each('cut,copy,paste'.split(','), function(i, name) {
		KCmd.prototype[name] = function() {
			var self = this;
			if (!self.doc.queryCommandSupported(name)) {
				throw 'not supported';
			}
			self.select();
			_nativeCommand(self.doc, name, null);
			return self;
		};
	});
	function _cmd(mixed) {
		if (mixed.nodeName) {
			var doc = _getDoc(mixed);
			mixed = _range(doc).selectNodeContents(doc.body).collapse(false);
		}
		return new KCmd(mixed);
	}
	K.CmdClass = KCmd;
	K.cmd = _cmd;
	function _drag(options) {
		var moveEl = options.moveEl, moveFn = options.moveFn, clickEl = options.clickEl
				|| moveEl, beforeDrag = options.beforeDrag, iframeFix = options.iframeFix === undefined ? true
				: options.iframeFix;
		var docs = [ document ];
		if (iframeFix) {
			K('iframe').each(function() {
				var src = _formatUrl(this.src || '', 'absolute');
				if (/^https?:\/\//.test(src)) {
					return;
				}
				var doc;
				try {
					doc = _iframeDoc(this);
				} catch (e) {
				}
				if (doc) {
					var pos = K(this).pos();
					K(doc).data('pos-x', pos.x);
					K(doc).data('pos-y', pos.y);
					docs.push(doc);
				}
			});
		}
		clickEl
				.mousedown(function(e) {
					e.stopPropagation();
					var self = clickEl.get(), x = _removeUnit(moveEl
							.css('left')), y = _removeUnit(moveEl.css('top')), width = moveEl
							.width(), height = moveEl.height(), pageX = e.pageX, pageY = e.pageY;
					if (beforeDrag) {
						beforeDrag();
					}
					function moveListener(e) {
						e.preventDefault();
						var kdoc = K(_getDoc(e.target));
						var diffX = _round((kdoc.data('pos-x') || 0) + e.pageX
								- pageX);
						var diffY = _round((kdoc.data('pos-y') || 0) + e.pageY
								- pageY);
						moveFn.call(clickEl, x, y, width, height, diffX, diffY);
					}
					function selectListener(e) {
						e.preventDefault();
					}
					function upListener(e) {
						e.preventDefault();
						K(docs).unbind('mousemove', moveListener).unbind(
								'mouseup', upListener).unbind('selectstart',
								selectListener);
						if (self.releaseCapture) {
							self.releaseCapture();
						}
					}
					K(docs).mousemove(moveListener).mouseup(upListener).bind(
							'selectstart', selectListener);
					if (self.setCapture) {
						self.setCapture();
					}
				});
	}
	function KWidget(options) {
		this.init(options);
	}
	_extend(
			KWidget,
			{
				init : function(options) {
					var self = this;
					self.name = options.name || '';
					self.doc = options.doc || document;
					self.win = _getWin(self.doc);
					self.x = _addUnit(options.x);
					self.y = _addUnit(options.y);
					self.z = options.z;
					self.width = _addUnit(options.width);
					self.height = _addUnit(options.height);
					self.div = K('<div style="display:block;"></div>');
					self.options = options;
					self._alignEl = options.alignEl;
					if (self.width) {
						self.div.css('width', self.width);
					}
					if (self.height) {
						self.div.css('height', self.height);
					}
					if (self.z) {
						self.div.css({
							position : 'absolute',
							left : self.x,
							top : self.y,
							'z-index' : self.z
						});
					}
					if (self.z
							&& (self.x === undefined || self.y === undefined)) {
						self.autoPos(self.width, self.height);
					}
					if (options.cls) {
						self.div.addClass(options.cls);
					}
					if (options.shadowMode) {
						self.div.addClass('ke-shadow');
					}
					if (options.css) {
						self.div.css(options.css);
					}
					if (options.src) {
						K(options.src).replaceWith(self.div);
					} else {
						K(self.doc.body).append(self.div);
					}
					if (options.html) {
						self.div.html(options.html);
					}
					if (options.autoScroll) {
						if (_IE && _V < 7 || _QUIRKS) {
							var scrollPos = _getScrollPos();
							K(self.win)
									.bind(
											'scroll',
											function(e) {
												var pos = _getScrollPos(), diffX = pos.x
														- scrollPos.x, diffY = pos.y
														- scrollPos.y;
												self.pos(_removeUnit(self.x)
														+ diffX,
														_removeUnit(self.y)
																+ diffY, false);
											});
						} else {
							self.div.css('position', 'fixed');
						}
					}
				},
				pos : function(x, y, updateProp) {
					var self = this;
					updateProp = _undef(updateProp, true);
					if (x !== null) {
						x = x < 0 ? 0 : _addUnit(x);
						self.div.css('left', x);
						if (updateProp) {
							self.x = x;
						}
					}
					if (y !== null) {
						y = y < 0 ? 0 : _addUnit(y);
						self.div.css('top', y);
						if (updateProp) {
							self.y = y;
						}
					}
					return self;
				},
				autoPos : function(width, height) {
					var self = this, w = _removeUnit(width) || 0, h = _removeUnit(height) || 0, scrollPos = _getScrollPos();
					if (self._alignEl) {
						var knode = K(self._alignEl), pos = knode.pos(), diffX = _round(knode[0].clientWidth
								/ 2 - w / 2), diffY = _round(knode[0].clientHeight
								/ 2 - h / 2);
						x = diffX < 0 ? pos.x : pos.x + diffX;
						y = diffY < 0 ? pos.y : pos.y + diffY;
					} else {
						var docEl = _docElement(self.doc);
						x = _round(scrollPos.x + (docEl.clientWidth - w) / 2);
						y = _round(scrollPos.y + (docEl.clientHeight - h) / 2);
					}
					if (!(_IE && _V < 7 || _QUIRKS)) {
						x -= scrollPos.x;
						y -= scrollPos.y;
					}
					return self.pos(x, y);
				},
				remove : function() {
					var self = this;
					if (_IE && _V < 7 || _QUIRKS) {
						K(self.win).unbind('scroll');
					}
					self.div.remove();
					_each(self, function(i) {
						self[i] = null;
					});
					return this;
				},
				show : function() {
					this.div.show();
					return this;
				},
				hide : function() {
					this.div.hide();
					return this;
				},
				draggable : function(options) {
					var self = this;
					options = options || {};
					options.moveEl = self.div;
					options.moveFn = function(x, y, width, height, diffX, diffY) {
						if ((x = x + diffX) < 0) {
							x = 0;
						}
						if ((y = y + diffY) < 0) {
							y = 0;
						}
						self.pos(x, y);
					};
					_drag(options);
					return self;
				}
			});
	function _widget(options) {
		return new KWidget(options);
	}
	K.WidgetClass = KWidget;
	K.widget = _widget;
	function _iframeDoc(iframe) {
		iframe = _get(iframe);
		return iframe.contentDocument || iframe.contentWindow.document;
	}
	var html, _direction = '';
	if ((html = document.getElementsByTagName('html'))) {
		_direction = html[0].dir;
	}
	function _getInitHtml(themesPath, bodyClass, cssPath, cssData) {
		var arr = [
				(_direction === '' ? '<html>' : '<html dir="' + _direction
						+ '">'),
				'<head><meta charset="utf-8" /><title></title>',
				'<style>',
				'html {margin:0;padding:0;}',
				'body {margin:0;padding:5px;}',
				'body, td {font:12px/1.5 "sans serif",tahoma,verdana,helvetica;}',
				'body, p, div {word-wrap: break-word;}', 'p {margin:5px 0;}',
				'table {border-collapse:collapse;}', 'img {border:0;}',
				'noscript {display:none;}',
				'table.ke-zeroborder td {border:1px dotted #AAA;}',
				'img.ke-flash {', '	border:1px solid #AAA;',
				'	background-image:url(' + themesPath + 'common/flash.gif);',
				'	background-position:center center;',
				'	background-repeat:no-repeat;', '	width:100px;',
				'	height:100px;', '}', 'img.ke-rm {',
				'	border:1px solid #AAA;',
				'	background-image:url(' + themesPath + 'common/rm.gif);',
				'	background-position:center center;',
				'	background-repeat:no-repeat;', '	width:100px;',
				'	height:100px;', '}', 'img.ke-media {',
				'	border:1px solid #AAA;',
				'	background-image:url(' + themesPath + 'common/media.gif);',
				'	background-position:center center;',
				'	background-repeat:no-repeat;', '	width:100px;',
				'	height:100px;', '}', 'img.ke-anchor {',
				'	border:1px dashed #666;', '	width:16px;', '	height:16px;',
				'}', '.ke-script, .ke-noscript, .ke-display-none {',
				'	display:none;', '	font-size:0;', '	width:0;', '	height:0;',
				'}', '.ke-pagebreak {', '	border:1px dotted #AAA;',
				'	font-size:0;', '	height:2px;', '}', '</style>' ];
		if (!_isArray(cssPath)) {
			cssPath = [ cssPath ];
		}
		_each(cssPath, function(i, path) {
			if (path) {
				arr.push('<link href="' + path + '" rel="stylesheet" />');
			}
		});
		if (cssData) {
			arr.push('<style>' + cssData + '</style>');
		}
		arr.push('</head><body '
				+ (bodyClass ? 'class="' + bodyClass + '"' : '')
				+ '></body></html>');
		return arr.join('\n');
	}
	function _elementVal(knode, val) {
		if (knode.hasVal()) {
			if (val === undefined) {
				var html = knode.val();
				html = html.replace(/(<(?:p|p\s[^>]*)>) *(<\/p>)/ig, '');
				return html;
			}
			return knode.val(val);
		}
		return knode.html(val);
	}
	function KEdit(options) {
		this.init(options);
	}
	_extend(
			KEdit,
			KWidget,
			{
				init : function(options) {
					var self = this;
					KEdit.parent.init.call(self, options);
					self.srcElement = K(options.srcElement);
					self.div.addClass('ke-edit');
					self.designMode = _undef(options.designMode, true);
					self.beforeGetHtml = options.beforeGetHtml;
					self.beforeSetHtml = options.beforeSetHtml;
					self.afterSetHtml = options.afterSetHtml;
					var themesPath = _undef(options.themesPath, ''), bodyClass = options.bodyClass, cssPath = options.cssPath, cssData = options.cssData, isDocumentDomain = location.protocol != 'res:'
							&& location.host.replace(/:\d+/, '') !== document.domain, srcScript = ('document.open();'
							+ (isDocumentDomain ? 'document.domain="'
									+ document.domain + '";' : '') + 'document.close();'), iframeSrc = _IE ? ' src="javascript:void(function(){'
							+ encodeURIComponent(srcScript) + '}())"'
							: '';
					self.iframe = K(
							'<iframe class="ke-edit-iframe" hidefocus="true" frameborder="0"'
									+ iframeSrc + '></iframe>').css('width',
							'100%');
					self.textarea = K(
							'<textarea class="ke-edit-textarea" hidefocus="true"></textarea>')
							.css('width', '100%');
					self.tabIndex = isNaN(parseInt(options.tabIndex, 10)) ? self.srcElement
							.attr('tabindex')
							: parseInt(options.tabIndex, 10);
					self.iframe.attr('tabindex', self.tabIndex);
					self.textarea.attr('tabindex', self.tabIndex);
					if (self.width) {
						self.setWidth(self.width);
					}
					if (self.height) {
						self.setHeight(self.height);
					}
					if (self.designMode) {
						self.textarea.hide();
					} else {
						self.iframe.hide();
					}
					function ready() {
						var doc = _iframeDoc(self.iframe);
						doc.open();
						if (isDocumentDomain) {
							doc.domain = document.domain;
						}
						doc.write(_getInitHtml(themesPath, bodyClass, cssPath,
								cssData));
						doc.close();
						self.win = self.iframe[0].contentWindow;
						self.doc = doc;
						var cmd = _cmd(doc);
						self.afterChange(function(e) {
							cmd.selection();
						});
						if (_WEBKIT) {
							K(doc).click(function(e) {
								if (K(e.target).name === 'img') {
									cmd.selection(true);
									cmd.range.selectNode(e.target);
									cmd.select();
								}
							});
						}
						if (_IE) {
							self._mousedownHandler = function() {
								var newRange = cmd.range.cloneRange();
								newRange.shrink();
								if (newRange.isControl()) {
									self.blur();
								}
							};
							K(document).mousedown(self._mousedownHandler);
							K(doc)
									.keydown(
											function(e) {
												if (e.which == 8) {
													cmd.selection();
													var rng = cmd.range;
													if (rng.isControl()) {
														rng.collapse(true);
														K(
																rng.startContainer.childNodes[rng.startOffset])
																.remove();
														e.preventDefault();
													}
												}
											});
						}
						self.cmd = cmd;
						self.html(_elementVal(self.srcElement));
						if (_IE) {
							doc.body.disabled = true;
							doc.body.contentEditable = true;
							doc.body.removeAttribute('disabled');
						} else {
							doc.designMode = 'on';
						}
						if (options.afterCreate) {
							options.afterCreate.call(self);
						}
					}
					if (isDocumentDomain) {
						self.iframe.bind('load', function(e) {
							self.iframe.unbind('load');
							if (_IE) {
								ready();
							} else {
								setTimeout(ready, 0);
							}
						});
					}
					self.div.append(self.iframe);
					self.div.append(self.textarea);
					self.srcElement.hide();
					!isDocumentDomain && ready();
				},
				setWidth : function(val) {
					var self = this;
					val = _addUnit(val);
					self.width = val;
					self.div.css('width', val);
					return self;
				},
				setHeight : function(val) {
					var self = this;
					val = _addUnit(val);
					self.height = val;
					self.div.css('height', val);
					self.iframe.css('height', val);
					if ((_IE && _V < 8) || _QUIRKS) {
						val = _addUnit(_removeUnit(val) - 2);
					}
					self.textarea.css('height', val);
					return self;
				},
				remove : function() {
					var self = this, doc = self.doc;
					K(doc.body).unbind();
					K(doc).unbind();
					K(self.win).unbind();
					if (self._mousedownHandler) {
						K(document).unbind('mousedown', self._mousedownHandler);
					}
					_elementVal(self.srcElement, self.html());
					self.srcElement.show();
					doc.write('');
					self.iframe.unbind();
					self.textarea.unbind();
					KEdit.parent.remove.call(self);
				},
				html : function(val, isFull) {
					var self = this, doc = self.doc;
					if (self.designMode) {
						var body = doc.body;
						if (val === undefined) {
							if (isFull) {
								val = '<!doctype html><html>'
										+ body.parentNode.innerHTML + '</html>';
							} else {
								val = body.innerHTML;
							}
							if (self.beforeGetHtml) {
								val = self.beforeGetHtml(val);
							}
							if (_GECKO && val == '<br />') {
								val = '';
							}
							return val;
						}
						if (self.beforeSetHtml) {
							val = self.beforeSetHtml(val);
						}
						if (_IE && _V >= 9) {
							val = val.replace(/(<.*?checked=")checked(".*>)/ig,
									'$1$2');
						}
						K(body).html(val);
						if (self.afterSetHtml) {
							self.afterSetHtml();
						}
						return self;
					}
					if (val === undefined) {
						return self.textarea.val();
					}
					self.textarea.val(val);
					return self;
				},
				design : function(bool) {
					var self = this, val;
					if (bool === undefined ? !self.designMode : bool) {
						if (!self.designMode) {
							val = self.html();
							self.designMode = true;
							self.html(val);
							self.textarea.hide();
							self.iframe.show();
						}
					} else {
						if (self.designMode) {
							val = self.html();
							self.designMode = false;
							self.html(val);
							self.iframe.hide();
							self.textarea.show();
						}
					}
					return self.focus();
				},
				focus : function() {
					var self = this;
					self.designMode ? self.win.focus() : self.textarea[0]
							.focus();
					return self;
				},
				blur : function() {
					var self = this;
					if (_IE) {
						var input = K(
								'<input type="text" style="float:left;width:0;height:0;padding:0;margin:0;border:0;" value="" />',
								self.div);
						self.div.append(input);
						input[0].focus();
						input.remove();
					} else {
						self.designMode ? self.win.blur() : self.textarea[0]
								.blur();
					}
					return self;
				},
				afterChange : function(fn) {
					var self = this, doc = self.doc, body = doc.body;
					K(doc).keyup(
							function(e) {
								if (!e.ctrlKey && !e.altKey
										&& _CHANGE_KEY_MAP[e.which]) {
									fn(e);
								}
							});
					K(doc).mouseup(fn).contextmenu(fn);
					K(self.win).blur(fn);
					function timeoutHandler(e) {
						setTimeout(function() {
							fn(e);
						}, 1);
					}
					K(body).bind('paste', timeoutHandler);
					K(body).bind('cut', timeoutHandler);
					return self;
				}
			});
	function _edit(options) {
		return new KEdit(options);
	}
	K.EditClass = KEdit;
	K.edit = _edit;
	K.iframeDoc = _iframeDoc;
	function _selectToolbar(name, fn) {
		var self = this, knode = self.get(name);
		if (knode) {
			if (knode.hasClass('ke-disabled')) {
				return;
			}
			fn(knode);
		}
	}
	function KToolbar(options) {
		this.init(options);
	}
	_extend(KToolbar, KWidget, {
		init : function(options) {
			var self = this;
			KToolbar.parent.init.call(self, options);
			self.disableMode = _undef(options.disableMode, false);
			self.noDisableItemMap = _toMap(_undef(options.noDisableItems, []));
			self._itemMap = {};
			self.div.addClass('ke-toolbar').bind(
					'contextmenu,mousedown,mousemove', function(e) {
						e.preventDefault();
					}).attr('unselectable', 'on');
			function find(target) {
				var knode = K(target);
				if (knode.hasClass('ke-outline')) {
					return knode;
				}
				if (knode.hasClass('ke-toolbar-icon')) {
					return knode.parent();
				}
			}
			function hover(e, method) {
				var knode = find(e.target);
				if (knode) {
					if (knode.hasClass('ke-disabled')) {
						return;
					}
					if (knode.hasClass('ke-selected')) {
						return;
					}
					knode[method]('ke-on');
				}
			}
			self.div.mouseover(function(e) {
				hover(e, 'addClass');
			}).mouseout(function(e) {
				hover(e, 'removeClass');
			}).click(function(e) {
				var knode = find(e.target);
				if (knode) {
					if (knode.hasClass('ke-disabled')) {
						return;
					}
					self.options.click.call(this, e, knode.attr('data-name'));
				}
			});
		},
		get : function(name) {
			if (this._itemMap[name]) {
				return this._itemMap[name];
			}
			return (this._itemMap[name] = K('span.ke-icon-' + name, this.div)
					.parent());
		},
		select : function(name) {
			_selectToolbar.call(this, name, function(knode) {
				knode.addClass('ke-selected');
			});
			return self;
		},
		unselect : function(name) {
			_selectToolbar.call(this, name, function(knode) {
				knode.removeClass('ke-selected').removeClass('ke-on');
			});
			return self;
		},
		enable : function(name) {
			var self = this, knode = name.get ? name : self.get(name);
			if (knode) {
				knode.removeClass('ke-disabled');
				knode.opacity(1);
			}
			return self;
		},
		disable : function(name) {
			var self = this, knode = name.get ? name : self.get(name);
			if (knode) {
				knode.removeClass('ke-selected').addClass('ke-disabled');
				knode.opacity(0.5);
			}
			return self;
		},
		disableAll : function(bool, noDisableItems) {
			var self = this, map = self.noDisableItemMap, item;
			if (noDisableItems) {
				map = _toMap(noDisableItems);
			}
			if (bool === undefined ? !self.disableMode : bool) {
				K('span.ke-outline', self.div).each(
						function() {
							var knode = K(this), name = knode[0].getAttribute(
									'data-name', 2);
							if (!map[name]) {
								self.disable(knode);
							}
						});
				self.disableMode = true;
			} else {
				K('span.ke-outline', self.div).each(
						function() {
							var knode = K(this), name = knode[0].getAttribute(
									'data-name', 2);
							if (!map[name]) {
								self.enable(knode);
							}
						});
				self.disableMode = false;
			}
			return self;
		}
	});
	function _toolbar(options) {
		return new KToolbar(options);
	}
	K.ToolbarClass = KToolbar;
	K.toolbar = _toolbar;
	function KMenu(options) {
		this.init(options);
	}
	_extend(
			KMenu,
			KWidget,
			{
				init : function(options) {
					var self = this;
					options.z = options.z || 811213;
					KMenu.parent.init.call(self, options);
					self.centerLineMode = _undef(options.centerLineMode, true);
					self.div.addClass('ke-menu').bind('click,mousedown',
							function(e) {
								e.stopPropagation();
							}).attr('unselectable', 'on');
				},
				addItem : function(item) {
					var self = this;
					if (item.title === '-') {
						self.div
								.append(K('<div class="ke-menu-separator"></div>'));
						return;
					}
					var itemDiv = K('<div class="ke-menu-item" unselectable="on"></div>'), leftDiv = K('<div class="ke-inline-block ke-menu-item-left"></div>'), rightDiv = K('<div class="ke-inline-block ke-menu-item-right"></div>'), height = _addUnit(item.height), iconClass = _undef(
							item.iconClass, '');
					self.div.append(itemDiv);
					if (height) {
						itemDiv.css('height', height);
						rightDiv.css('line-height', height);
					}
					var centerDiv;
					if (self.centerLineMode) {
						centerDiv = K('<div class="ke-inline-block ke-menu-item-center"></div>');
						if (height) {
							centerDiv.css('height', height);
						}
					}
					itemDiv.mouseover(function(e) {
						K(this).addClass('ke-menu-item-on');
						if (centerDiv) {
							centerDiv.addClass('ke-menu-item-center-on');
						}
					}).mouseout(function(e) {
						K(this).removeClass('ke-menu-item-on');
						if (centerDiv) {
							centerDiv.removeClass('ke-menu-item-center-on');
						}
					}).click(function(e) {
						item.click.call(K(this));
						e.stopPropagation();
					}).append(leftDiv);
					if (centerDiv) {
						itemDiv.append(centerDiv);
					}
					itemDiv.append(rightDiv);
					if (item.checked) {
						iconClass = 'ke-icon-checked';
					}
					if (iconClass !== '') {
						leftDiv
								.html('<span class="ke-inline-block ke-toolbar-icon ke-toolbar-icon-url '
										+ iconClass + '"></span>');
					}
					rightDiv.html(item.title);
					return self;
				},
				remove : function() {
					var self = this;
					if (self.options.beforeRemove) {
						self.options.beforeRemove.call(self);
					}
					K('.ke-menu-item', self.div[0]).unbind();
					KMenu.parent.remove.call(self);
					return self;
				}
			});
	function _menu(options) {
		return new KMenu(options);
	}
	K.MenuClass = KMenu;
	K.menu = _menu;
	function KColorPicker(options) {
		this.init(options);
	}
	_extend(
			KColorPicker,
			KWidget,
			{
				init : function(options) {
					var self = this;
					options.z = options.z || 811213;
					KColorPicker.parent.init.call(self, options);
					var colors = options.colors
							|| [
									[ '#E53333', '#E56600', '#FF9900',
											'#64451D', '#DFC5A4', '#FFE500' ],
									[ '#009900', '#006600', '#99BB00',
											'#B8D100', '#60D978', '#00D5FF' ],
									[ '#337FE5', '#003399', '#4C33E5',
											'#9933E5', '#CC33E5', '#EE33EE' ],
									[ '#FFFFFF', '#CCCCCC', '#999999',
											'#666666', '#333333', '#000000' ] ];
					self.selectedColor = (options.selectedColor || '')
							.toLowerCase();
					self._cells = [];
					self.div.addClass('ke-colorpicker').bind('click,mousedown',
							function(e) {
								e.stopPropagation();
							}).attr('unselectable', 'on');
					var table = self.doc.createElement('table');
					self.div.append(table);
					table.className = 'ke-colorpicker-table';
					table.cellPadding = 0;
					table.cellSpacing = 0;
					table.border = 0;
					var row = table.insertRow(0), cell = row.insertCell(0);
					cell.colSpan = colors[0].length;
					self._addAttr(cell, '', 'ke-colorpicker-cell-top');
					for (var i = 0; i < colors.length; i++) {
						row = table.insertRow(i + 1);
						for (var j = 0; j < colors[i].length; j++) {
							cell = row.insertCell(j);
							self._addAttr(cell, colors[i][j],
									'ke-colorpicker-cell');
						}
					}
				},
				_addAttr : function(cell, color, cls) {
					var self = this;
					cell = K(cell).addClass(cls);
					if (self.selectedColor === color.toLowerCase()) {
						cell.addClass('ke-colorpicker-cell-selected');
					}
					cell.attr('title', color || self.options.noColor);
					cell.mouseover(function(e) {
						K(this).addClass('ke-colorpicker-cell-on');
					});
					cell.mouseout(function(e) {
						K(this).removeClass('ke-colorpicker-cell-on');
					});
					cell.click(function(e) {
						e.stop();
						self.options.click.call(K(this), color);
					});
					if (color) {
						cell
								.append(K(
										'<div class="ke-colorpicker-cell-color" unselectable="on"></div>')
										.css('background-color', color));
					} else {
						cell.html(self.options.noColor);
					}
					K(cell).attr('unselectable', 'on');
					self._cells.push(cell);
				},
				remove : function() {
					var self = this;
					_each(self._cells, function() {
						this.unbind();
					});
					KColorPicker.parent.remove.call(self);
					return self;
				}
			});
	function _colorpicker(options) {
		return new KColorPicker(options);
	}
	K.ColorPickerClass = KColorPicker;
	K.colorpicker = _colorpicker;
	function KUploadButton(options) {
		this.init(options);
	}
	_extend(
			KUploadButton,
			{
				init : function(options) {
					var self = this, button = K(options.button), fieldName = options.fieldName
							|| 'file', url = options.url || '', title = button
							.val(), extraParams = options.extraParams || {}, cls = button[0].className
							|| '', target = options.target
							|| 'kindeditor_upload_iframe_'
							+ new Date().getTime();
					options.afterError = options.afterError || function(str) {
						alert(str);
					};
					var hiddenElements = [];
					for ( var k in extraParams) {
						hiddenElements.push('<input type="hidden" name="' + k
								+ '" value="' + extraParams[k] + '" />');
					}
					var html = [
							'<div class="ke-inline-block ' + cls + '">',
							(options.target ? '' : '<iframe name="' + target
									+ '" style="display:none;"></iframe>'),
							(options.form ? '<div class="ke-upload-area">'
									: '<form class="ke-upload-area ke-form" method="post" enctype="multipart/form-data" target="'
											+ target
											+ '" action="'
											+ url
											+ '">'),
							'<span class="ke-button-common">',
							hiddenElements.join(''),
							'<input type="button" class="ke-button-common ke-button" value="'
									+ title + '" />',
							'</span>',
							'<input type="file" class="ke-upload-file" name="'
									+ fieldName + '" tabindex="-1" />',
							(options.form ? '</div>' : '</form>'), '</div>' ]
							.join('');
					var div = K(html, button.doc);
					button.hide();
					button.before(div);
					self.div = div;
					self.button = button;
					self.iframe = options.target ? K('iframe[name="' + target
							+ '"]') : K('iframe', div);
					self.form = options.form ? K(options.form) : K('form', div);
					self.fileBox = K('.ke-upload-file', div);
					var width = options.width
							|| K('.ke-button-common', div).width();
					K('.ke-upload-area', div).width(width);
					self.options = options;
				},
				submit : function() {
					var self = this, iframe = self.iframe;
					iframe
							.bind(
									'load',
									function() {
										iframe.unbind();
										var tempForm = document
												.createElement('form');
										self.fileBox.before(tempForm);
										K(tempForm).append(self.fileBox);
										tempForm.reset();
										K(tempForm).remove(true);
										var doc = K.iframeDoc(iframe), pre = doc
												.getElementsByTagName('pre')[0], str = '', data;
										if (pre) {
											str = pre.innerHTML;
										} else {
											str = doc.body.innerHTML;
										}
										str = _unescape(str);
										iframe[0].src = 'javascript:false';
										try {
											data = K.json(str);
										} catch (e) {
											self.options.afterError
													.call(
															self,
															'<!doctype html><html>'
																	+ doc.body.parentNode.innerHTML
																	+ '</html>');
										}
										if (data) {
											self.options.afterUpload.call(self,
													data);
										}
									});
					self.form[0].submit();
					return self;
				},
				remove : function() {
					var self = this;
					if (self.fileBox) {
						self.fileBox.unbind();
					}
					self.iframe.remove();
					self.div.remove();
					self.button.show();
					return self;
				}
			});
	function _uploadbutton(options) {
		return new KUploadButton(options);
	}
	K.UploadButtonClass = KUploadButton;
	K.uploadbutton = _uploadbutton;
	function _createButton(arg) {
		arg = arg || {};
		var name = arg.name || '', span = K('<span class="ke-button-common ke-button-outer" title="'
				+ name + '"></span>'), btn = K('<input class="ke-button-common ke-button" type="button" value="'
				+ name + '" />');
		if (arg.click) {
			btn.click(arg.click);
		}
		span.append(btn);
		return span;
	}
	function KDialog(options) {
		this.init(options);
	}
	_extend(
			KDialog,
			KWidget,
			{
				init : function(options) {
					var self = this;
					var shadowMode = _undef(options.shadowMode, true);
					options.z = options.z || 811213;
					options.shadowMode = false;
					options.autoScroll = _undef(options.autoScroll, true);
					KDialog.parent.init.call(self, options);
					var title = options.title, body = K(options.body, self.doc), previewBtn = options.previewBtn, yesBtn = options.yesBtn, noBtn = options.noBtn, closeBtn = options.closeBtn, showMask = _undef(
							options.showMask, true);
					self.div.addClass('ke-dialog').bind('click,mousedown',
							function(e) {
								e.stopPropagation();
							});
					var contentDiv = K('<div class="ke-dialog-content"></div>')
							.appendTo(self.div);
					if (_IE && _V < 7) {
						self.iframeMask = K(
								'<iframe src="about:blank" class="ke-dialog-shadow"></iframe>')
								.appendTo(self.div);
					} else if (shadowMode) {
						K('<div class="ke-dialog-shadow"></div>').appendTo(
								self.div);
					}
					var headerDiv = K('<div class="ke-dialog-header"></div>');
					contentDiv.append(headerDiv);
					headerDiv.html(title);
					self.closeIcon = K(
							'<span class="ke-dialog-icon-close" title="'
									+ closeBtn.name + '"></span>').click(
							closeBtn.click);
					headerDiv.append(self.closeIcon);
					self.draggable({
						clickEl : headerDiv,
						beforeDrag : options.beforeDrag
					});
					var bodyDiv = K('<div class="ke-dialog-body"></div>');
					contentDiv.append(bodyDiv);
					bodyDiv.append(body);
					var footerDiv = K('<div class="ke-dialog-footer"></div>');
					if (previewBtn || yesBtn || noBtn) {
						contentDiv.append(footerDiv);
					}
					_each([ {
						btn : previewBtn,
						name : 'preview'
					}, {
						btn : yesBtn,
						name : 'yes'
					}, {
						btn : noBtn,
						name : 'no'
					} ], function() {
						if (this.btn) {
							var button = _createButton(this.btn);
							button.addClass('ke-dialog-' + this.name);
							footerDiv.append(button);
						}
					});
					if (self.height) {
						bodyDiv.height(_removeUnit(self.height)
								- headerDiv.height() - footerDiv.height());
					}
					self.div.width(self.div.width());
					self.div.height(self.div.height());
					self.mask = null;
					if (showMask) {
						var docEl = _docElement(self.doc), docWidth = Math.max(
								docEl.scrollWidth, docEl.clientWidth), docHeight = Math
								.max(docEl.scrollHeight, docEl.clientHeight);
						self.mask = _widget({
							x : 0,
							y : 0,
							z : self.z - 1,
							cls : 'ke-dialog-mask',
							width : docWidth,
							height : docHeight
						});
					}
					self.autoPos(self.div.width(), self.div.height());
					self.footerDiv = footerDiv;
					self.bodyDiv = bodyDiv;
					self.headerDiv = headerDiv;
					self.isLoading = false;
				},
				setMaskIndex : function(z) {
					var self = this;
					self.mask.div.css('z-index', z);
				},
				showLoading : function(msg) {
					msg = _undef(msg, '');
					var self = this, body = self.bodyDiv;
					self.loading = K(
							'<div class="ke-dialog-loading"><div class="ke-inline-block ke-dialog-loading-content" style="margin-top:'
									+ Math.round(body.height() / 3)
									+ 'px;">'
									+ msg + '</div></div>').width(body.width())
							.height(body.height()).css('top',
									self.headerDiv.height() + 'px');
					body.css('visibility', 'hidden').after(self.loading);
					self.isLoading = true;
					return self;
				},
				hideLoading : function() {
					this.loading && this.loading.remove();
					this.bodyDiv.css('visibility', 'visible');
					this.isLoading = false;
					return this;
				},
				remove : function() {
					var self = this;
					if (self.options.beforeRemove) {
						self.options.beforeRemove.call(self);
					}
					self.mask && self.mask.remove();
					self.iframeMask && self.iframeMask.remove();
					self.closeIcon.unbind();
					K('input', self.div).unbind();
					K('button', self.div).unbind();
					self.footerDiv.unbind();
					self.bodyDiv.unbind();
					self.headerDiv.unbind();
					K('iframe', self.div).each(function() {
						K(this).remove();
					});
					KDialog.parent.remove.call(self);
					return self;
				}
			});
	function _dialog(options) {
		return new KDialog(options);
	}
	K.DialogClass = KDialog;
	K.dialog = _dialog;
	function _tabs(options) {
		var self = _widget(options), remove = self.remove, afterSelect = options.afterSelect, div = self.div, liList = [];
		div.addClass('ke-tabs').bind('contextmenu,mousedown,mousemove',
				function(e) {
					e.preventDefault();
				});
		var ul = K('<ul class="ke-tabs-ul ke-clearfix"></ul>');
		div.append(ul);
		self.add = function(tab) {
			var li = K('<li class="ke-tabs-li">' + tab.title + '</li>');
			li.data('tab', tab);
			liList.push(li);
			ul.append(li);
		};
		self.selectedIndex = 0;
		self.select = function(index) {
			self.selectedIndex = index;
			_each(liList, function(i, li) {
				li.unbind();
				if (i === index) {
					li.addClass('ke-tabs-li-selected');
					K(li.data('tab').panel).show('');
				} else {
					li.removeClass('ke-tabs-li-selected').removeClass(
							'ke-tabs-li-on').mouseover(function() {
						K(this).addClass('ke-tabs-li-on');
					}).mouseout(function() {
						K(this).removeClass('ke-tabs-li-on');
					}).click(function() {
						self.select(i);
					});
					K(li.data('tab').panel).hide();
				}
			});
			if (afterSelect) {
				afterSelect.call(self, index);
			}
		};
		self.remove = function() {
			_each(liList, function() {
				this.remove();
			});
			ul.remove();
			remove.call(self);
		};
		return self;
	}
	K.tabs = _tabs;
	function _loadScript(url, fn) {
		var head = document.getElementsByTagName('head')[0]
				|| (_QUIRKS ? document.body : document.documentElement), script = document
				.createElement('script');
		head.appendChild(script);
		script.src = url;
		script.charset = 'utf-8';
		script.onload = script.onreadystatechange = function() {
			if (!this.readyState || this.readyState === 'loaded') {
				if (fn) {
					fn();
				}
				script.onload = script.onreadystatechange = null;
				head.removeChild(script);
			}
		};
	}
	function _chopQuery(url) {
		var index = url.indexOf('?');
		return index > 0 ? url.substr(0, index) : url;
	}
	function _loadStyle(url) {
		var head = document.getElementsByTagName('head')[0]
				|| (_QUIRKS ? document.body : document.documentElement), link = document
				.createElement('link'), absoluteUrl = _chopQuery(_formatUrl(
				url, 'absolute'));
		var links = K('link[rel="stylesheet"]', head);
		for (var i = 0, len = links.length; i < len; i++) {
			if (_chopQuery(_formatUrl(links[i].href, 'absolute')) === absoluteUrl) {
				return;
			}
		}
		head.appendChild(link);
		link.href = url;
		link.rel = 'stylesheet';
	}
	function _ajax(url, fn, method, param, dataType) {
		method = method || 'GET';
		dataType = dataType || 'json';
		var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest()
				: new ActiveXObject('Microsoft.XMLHTTP');
		xhr.open(method, url, true);
		xhr.onreadystatechange = function() {
			if (xhr.readyState == 4 && xhr.status == 200) {
				if (fn) {
					var data = _trim(xhr.responseText);
					if (dataType == 'json') {
						data = _json(data);
					}
					fn(data);
				}
			}
		};
		if (method == 'POST') {
			var params = [];
			_each(param, function(key, val) {
				params.push(encodeURIComponent(key) + '='
						+ encodeURIComponent(val));
			});
			try {
				xhr.setRequestHeader('Content-Type',
						'application/x-www-form-urlencoded');
			} catch (e) {
			}
			xhr.send(params.join('&'));
		} else {
			xhr.send(null);
		}
	}
	K.loadScript = _loadScript;
	K.loadStyle = _loadStyle;
	K.ajax = _ajax;
	var _plugins = {};
	function _plugin(name, fn) {
		if (name === undefined) {
			return _plugins;
		}
		if (!fn) {
			return _plugins[name];
		}
		_plugins[name] = fn;
	}
	var _language = {};
	function _parseLangKey(key) {
		var match, ns = 'core';
		if ((match = /^(\w+)\.(\w+)$/.exec(key))) {
			ns = match[1];
			key = match[2];
		}
		return {
			ns : ns,
			key : key
		};
	}
	function _lang(mixed, langType) {
		langType = langType === undefined ? K.options.langType : langType;
		if (typeof mixed === 'string') {
			if (!_language[langType]) {
				return 'no language';
			}
			var pos = mixed.length - 1;
			if (mixed.substr(pos) === '.') {
				return _language[langType][mixed.substr(0, pos)];
			}
			var obj = _parseLangKey(mixed);
			return _language[langType][obj.ns][obj.key];
		}
		_each(mixed, function(key, val) {
			var obj = _parseLangKey(key);
			if (!_language[langType]) {
				_language[langType] = {};
			}
			if (!_language[langType][obj.ns]) {
				_language[langType][obj.ns] = {};
			}
			_language[langType][obj.ns][obj.key] = val;
		});
	}
	function _getImageFromRange(range, fn) {
		if (range.collapsed) {
			return;
		}
		range = range.cloneRange().up();
		var sc = range.startContainer, so = range.startOffset;
		if (!_WEBKIT && !range.isControl()) {
			return;
		}
		var img = K(sc.childNodes[so]);
		if (!img || img.name != 'img') {
			return;
		}
		if (fn(img)) {
			return img;
		}
	}
	function _bindContextmenuEvent() {
		var self = this, doc = self.edit.doc;
		K(doc)
				.contextmenu(
						function(e) {
							if (self.menu) {
								self.hideMenu();
							}
							if (!self.useContextmenu) {
								e.preventDefault();
								return;
							}
							if (self._contextmenus.length === 0) {
								return;
							}
							var maxWidth = 0, items = [];
							_each(self._contextmenus, function() {
								if (this.title == '-') {
									items.push(this);
									return;
								}
								if (this.cond && this.cond()) {
									items.push(this);
									if (this.width && this.width > maxWidth) {
										maxWidth = this.width;
									}
								}
							});
							while (items.length > 0 && items[0].title == '-') {
								items.shift();
							}
							while (items.length > 0
									&& items[items.length - 1].title == '-') {
								items.pop();
							}
							var prevItem = null;
							_each(items,
									function(i) {
										if (this.title == '-'
												&& prevItem.title == '-') {
											delete items[i];
										}
										prevItem = this;
									});
							if (items.length > 0) {
								e.preventDefault();
								var pos = K(self.edit.iframe).pos(), menu = _menu({
									x : pos.x + e.clientX,
									y : pos.y + e.clientY,
									width : maxWidth,
									css : {
										visibility : 'hidden'
									},
									shadowMode : self.shadowMode
								});
								_each(items, function() {
									if (this.title) {
										menu.addItem(this);
									}
								});
								var docEl = _docElement(menu.doc), menuHeight = menu.div
										.height();
								if (e.clientY + menuHeight >= docEl.clientHeight - 100) {
									menu.pos(menu.x, _removeUnit(menu.y)
											- menuHeight);
								}
								menu.div.css('visibility', 'visible');
								self.menu = menu;
							}
						});
	}
	function _bindNewlineEvent() {
		var self = this, doc = self.edit.doc, newlineTag = self.newlineTag;
		if (_IE && newlineTag !== 'br') {
			return;
		}
		if (_GECKO && _V < 3 && newlineTag !== 'p') {
			return;
		}
		if (_OPERA && _V < 9) {
			return;
		}
		var brSkipTagMap = _toMap('h1,h2,h3,h4,h5,h6,pre,li'), pSkipTagMap = _toMap('p,h1,h2,h3,h4,h5,h6,pre,li,blockquote');
		function getAncestorTagName(range) {
			var ancestor = K(range.commonAncestor());
			while (ancestor) {
				if (ancestor.type == 1 && !ancestor.isStyle()) {
					break;
				}
				ancestor = ancestor.parent();
			}
			return ancestor.name;
		}
		K(doc).keydown(function(e) {
			if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) {
				return;
			}
			self.cmd.selection();
			var tagName = getAncestorTagName(self.cmd.range);
			if (tagName == 'marquee' || tagName == 'select') {
				return;
			}
			if (newlineTag === 'br' && !brSkipTagMap[tagName]) {
				e.preventDefault();
				self.insertHtml('<br />' + (_IE && _V < 9 ? '' : '\u200B'));
				return;
			}
			if (!pSkipTagMap[tagName]) {
				_nativeCommand(doc, 'formatblock', '<p>');
			}
		});
		K(doc).keyup(function(e) {
			if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) {
				return;
			}
			if (newlineTag == 'br') {
				return;
			}
			if (_GECKO) {
				var root = self.cmd.commonAncestor('p');
				var a = self.cmd.commonAncestor('a');
				if (a && a.text() == '') {
					a.remove(true);
					self.cmd.range.selectNodeContents(root[0]).collapse(true);
					self.cmd.select();
				}
				return;
			}
			self.cmd.selection();
			var tagName = getAncestorTagName(self.cmd.range);
			if (tagName == 'marquee' || tagName == 'select') {
				return;
			}
			if (!pSkipTagMap[tagName]) {
				_nativeCommand(doc, 'formatblock', '<p>');
			}
			var div = self.cmd.commonAncestor('div');
			if (div) {
				var p = K('<p></p>'), child = div[0].firstChild;
				while (child) {
					var next = child.nextSibling;
					p.append(child);
					child = next;
				}
				div.before(p);
				div.remove();
				self.cmd.range.selectNodeContents(p[0]);
				self.cmd.select();
			}
		});
	}
	function _bindTabEvent() {
		var self = this, doc = self.edit.doc;
		K(doc).keydown(function(e) {
			if (e.which == 9) {
				e.preventDefault();
				if (self.afterTab) {
					self.afterTab.call(self, e);
					return;
				}
				var cmd = self.cmd, range = cmd.range;
				range.shrink();
				if (range.collapsed && range.startContainer.nodeType == 1) {
					range.insertNode(K('@&nbsp;', doc)[0]);
					cmd.select();
				}
				self.insertHtml('&nbsp;&nbsp;&nbsp;&nbsp;');
			}
		});
	}
	function _bindFocusEvent() {
		var self = this;
		K(self.edit.textarea[0], self.edit.win).focus(function(e) {
			if (self.afterFocus) {
				self.afterFocus.call(self, e);
			}
		}).blur(function(e) {
			if (self.afterBlur) {
				self.afterBlur.call(self, e);
			}
		});
	}
	function _removeBookmarkTag(html) {
		return _trim(html
				.replace(
						/<span [^>]*id="?__kindeditor_bookmark_\w+_\d+__"?[^>]*><\/span>/ig,
						''));
	}
	function _removeTempTag(html) {
		return html
				.replace(
						/<div[^>]+class="?__kindeditor_paste__"?[^>]*>[\s\S]*?<\/div>/ig,
						'');
	}
	function _addBookmarkToStack(stack, bookmark) {
		if (stack.length === 0) {
			stack.push(bookmark);
			return;
		}
		var prev = stack[stack.length - 1];
		if (_removeBookmarkTag(bookmark.html) !== _removeBookmarkTag(prev.html)) {
			stack.push(bookmark);
		}
	}
	function _undoToRedo(fromStack, toStack) {
		var self = this, edit = self.edit, body = edit.doc.body, range, bookmark;
		if (fromStack.length === 0) {
			return self;
		}
		if (edit.designMode) {
			range = self.cmd.range;
			bookmark = range.createBookmark(true);
			bookmark.html = body.innerHTML;
		} else {
			bookmark = {
				html : body.innerHTML
			};
		}
		_addBookmarkToStack(toStack, bookmark);
		var prev = fromStack.pop();
		if (_removeBookmarkTag(bookmark.html) === _removeBookmarkTag(prev.html)
				&& fromStack.length > 0) {
			prev = fromStack.pop();
		}
		if (edit.designMode) {
			edit.html(prev.html);
			if (prev.start) {
				range.moveToBookmark(prev);
				self.select();
			}
		} else {
			K(body).html(_removeBookmarkTag(prev.html));
		}
		return self;
	}
	function KEditor(options) {
		var self = this;
		self.options = {};
		function setOption(key, val) {
			if (KEditor.prototype[key] === undefined) {
				self[key] = val;
			}
			self.options[key] = val;
		}
		_each(options, function(key, val) {
			setOption(key, options[key]);
		});
		_each(K.options, function(key, val) {
			if (self[key] === undefined) {
				setOption(key, val);
			}
		});
		var se = K(self.srcElement || '<textarea/>');
		if (!self.width) {
			self.width = se[0].style.width || se.width();
		}
		if (!self.height) {
			self.height = se[0].style.height || se.height();
		}
		setOption('width', _undef(self.width, self.minWidth));
		setOption('height', _undef(self.height, self.minHeight));
		setOption('width', _addUnit(self.width));
		setOption('height', _addUnit(self.height));
		if (_MOBILE && (!_IOS || _V < 534)) {
			self.designMode = false;
		}
		self.srcElement = se;
		self.initContent = '';
		self.plugin = {};
		self.isCreated = false;
		self._handlers = {};
		self._contextmenus = [];
		self._undoStack = [];
		self._redoStack = [];
		self._firstAddBookmark = true;
		self.menu = self.contextmenu = null;
		self.dialogs = [];
	}
	KEditor.prototype = {
		lang : function(mixed) {
			return _lang(mixed, this.langType);
		},
		loadPlugin : function(name, fn) {
			var self = this;
			if (_plugins[name]) {
				if (!_isFunction(_plugins[name])) {
					setTimeout(function() {
						self.loadPlugin(name, fn);
					}, 100);
					return self;
				}
				_plugins[name].call(self, KindEditor);
				if (fn) {
					fn.call(self);
				}
				return self;
			}
			_plugins[name] = 'loading';
			_loadScript(self.pluginsPath + name + '/' + name + '.js?ver='
					+ encodeURIComponent(K.DEBUG ? _TIME : _VERSION),
					function() {
						setTimeout(function() {
							if (_plugins[name]) {
								self.loadPlugin(name, fn);
							}
						}, 0);
					});
			return self;
		},
		handler : function(key, fn) {
			var self = this;
			if (!self._handlers[key]) {
				self._handlers[key] = [];
			}
			if (_isFunction(fn)) {
				self._handlers[key].push(fn);
				return self;
			}
			_each(self._handlers[key], function() {
				fn = this.call(self, fn);
			});
			return fn;
		},
		clickToolbar : function(name, fn) {
			var self = this, key = 'clickToolbar' + name;
			if (fn === undefined) {
				if (self._handlers[key]) {
					return self.handler(key);
				}
				self.loadPlugin(name, function() {
					self.handler(key);
				});
				return self;
			}
			return self.handler(key, fn);
		},
		updateState : function() {
			var self = this;
			_each(
					('justifyleft,justifycenter,justifyright,justifyfull,insertorderedlist,insertunorderedlist,'
							+ 'subscript,superscript,bold,italic,underline,strikethrough')
							.split(','), function(i, name) {
						self.cmd.state(name) ? self.toolbar.select(name)
								: self.toolbar.unselect(name);
					});
			return self;
		},
		addContextmenu : function(item) {
			this._contextmenus.push(item);
			return this;
		},
		afterCreate : function(fn) {
			return this.handler('afterCreate', fn);
		},
		beforeRemove : function(fn) {
			return this.handler('beforeRemove', fn);
		},
		beforeGetHtml : function(fn) {
			return this.handler('beforeGetHtml', fn);
		},
		beforeSetHtml : function(fn) {
			return this.handler('beforeSetHtml', fn);
		},
		afterSetHtml : function(fn) {
			return this.handler('afterSetHtml', fn);
		},
		create : function() {
			var self = this, fullscreenMode = self.fullscreenMode;
			if (self.isCreated) {
				return self;
			}
			if (self.srcElement.data('kindeditor')) {
				return self;
			}
			self.srcElement.data('kindeditor', 'true');
			if (fullscreenMode) {
				_docElement().style.overflow = 'hidden';
			} else {
				_docElement().style.overflow = '';
			}
			var width = fullscreenMode ? _docElement().clientWidth + 'px'
					: self.width, height = fullscreenMode ? _docElement().clientHeight
					+ 'px'
					: self.height;
			if ((_IE && _V < 8) || _QUIRKS) {
				height = _addUnit(_removeUnit(height) + 2);
			}
			var container = self.container = K(self.layout);
			if (fullscreenMode) {
				K(document.body).append(container);
			} else {
				self.srcElement.before(container);
			}
			var toolbarDiv = K('.toolbar', container), editDiv = K('.edit',
					container), statusbar = self.statusbar = K('.statusbar',
					container);
			container.removeClass('container').addClass(
					'ke-container ke-container-' + self.themeType).css('width',
					width);
			if (fullscreenMode) {
				container.css({
					position : 'absolute',
					left : 0,
					top : 0,
					'z-index' : 811211
				});
				if (!_GECKO) {
					self._scrollPos = _getScrollPos();
				}
				window.scrollTo(0, 0);
				K(document.body).css({
					'height' : '1px',
					'overflow' : 'hidden'
				});
				K(document.body.parentNode).css('overflow', 'hidden');
				self._fullscreenExecuted = true;
			} else {
				if (self._fullscreenExecuted) {
					K(document.body).css({
						'height' : '',
						'overflow' : ''
					});
					K(document.body.parentNode).css('overflow', '');
				}
				if (self._scrollPos) {
					window.scrollTo(self._scrollPos.x, self._scrollPos.y);
				}
			}
			var htmlList = [];
			K
					.each(
							self.items,
							function(i, name) {
								if (name == '|') {
									htmlList
											.push('<span class="ke-inline-block ke-separator"></span>');
								} else if (name == '/') {
									htmlList.push('<div class="ke-hr"></div>');
								} else {
									htmlList
											.push('<span class="ke-outline" data-name="'
													+ name
													+ '" title="'
													+ self.lang(name)
													+ '" unselectable="on">');
									htmlList
											.push('<span class="ke-toolbar-icon ke-toolbar-icon-url ke-icon-'
													+ name
													+ '" unselectable="on"></span></span>');
								}
							});
			var toolbar = self.toolbar = _toolbar({
				src : toolbarDiv,
				html : htmlList.join(''),
				noDisableItems : self.noDisableItems,
				click : function(e, name) {
					e.stop();
					if (self.menu) {
						var menuName = self.menu.name;
						self.hideMenu();
						if (menuName === name) {
							return;
						}
					}
					self.clickToolbar(name);
				}
			});
			var editHeight = _removeUnit(height) - toolbar.div.height();
			var edit = self.edit = _edit({
				height : editHeight > 0 && _removeUnit(height) > self.minHeight ? editHeight
						: self.minHeight,
				src : editDiv,
				srcElement : self.srcElement,
				designMode : self.designMode,
				themesPath : self.themesPath,
				bodyClass : self.bodyClass,
				cssPath : self.cssPath,
				cssData : self.cssData,
				beforeGetHtml : function(html) {
					html = self.beforeGetHtml(html);
					html = _removeBookmarkTag(_removeTempTag(html));
					return _formatHtml(html, self.filterMode ? self.htmlTags
							: null, self.urlType, self.wellFormatMode,
							self.indentChar);
				},
				beforeSetHtml : function(html) {
					html = _formatHtml(html, self.filterMode ? self.htmlTags
							: null, '', false);
					return self.beforeSetHtml(html);
				},
				afterSetHtml : function() {
					self.edit = edit = this;
					self.afterSetHtml();
				},
				afterCreate : function() {
					self.edit = edit = this;
					self.cmd = edit.cmd;
					self._docMousedownFn = function(e) {
						if (self.menu) {
							self.hideMenu();
						}
					};
					K(edit.doc, document).mousedown(self._docMousedownFn);
					_bindContextmenuEvent.call(self);
					_bindNewlineEvent.call(self);
					_bindTabEvent.call(self);
					_bindFocusEvent.call(self);
					edit.afterChange(function(e) {
						if (!edit.designMode) {
							return;
						}
						self.updateState();
						self.addBookmark();
						if (self.options.afterChange) {
							self.options.afterChange.call(self);
						}
					});
					edit.textarea
							.keyup(function(e) {
								if (!e.ctrlKey && !e.altKey
										&& _INPUT_KEY_MAP[e.which]) {
									if (self.options.afterChange) {
										self.options.afterChange.call(self);
									}
								}
							});
					if (self.readonlyMode) {
						self.readonly();
					}
					self.isCreated = true;
					if (self.initContent === '') {
						self.initContent = self.html();
					}
					if (self._undoStack.length > 0) {
						var prev = self._undoStack.pop();
						if (prev.start) {
							self.html(prev.html);
							edit.cmd.range.moveToBookmark(prev);
							self.select();
						}
					}
					self.afterCreate();
					if (self.options.afterCreate) {
						self.options.afterCreate.call(self);
					}
				}
			});
			statusbar
					.removeClass('statusbar')
					.addClass('ke-statusbar')
					.append(
							'<span class="ke-inline-block ke-statusbar-center-icon"></span>')
					.append(
							'<span class="ke-inline-block ke-statusbar-right-icon"></span>');
			if (self._fullscreenResizeHandler) {
				K(window).unbind('resize', self._fullscreenResizeHandler);
				self._fullscreenResizeHandler = null;
			}
			function initResize() {
				if (statusbar.height() === 0) {
					setTimeout(initResize, 100);
					return;
				}
				self.resize(width, height, false);
			}
			initResize();
			if (fullscreenMode) {
				self._fullscreenResizeHandler = function(e) {
					if (self.isCreated) {
						self.resize(_docElement().clientWidth,
								_docElement().clientHeight, false);
					}
				};
				K(window).bind('resize', self._fullscreenResizeHandler);
				toolbar.select('fullscreen');
				statusbar.first().css('visibility', 'hidden');
				statusbar.last().css('visibility', 'hidden');
			} else {
				if (_GECKO) {
					K(window).bind('scroll', function(e) {
						self._scrollPos = _getScrollPos();
					});
				}
				if (self.resizeType > 0) {
					_drag({
						moveEl : container,
						clickEl : statusbar,
						moveFn : function(x, y, width, height, diffX, diffY) {
							height += diffY;
							self.resize(null, height);
						}
					});
				} else {
					statusbar.first().css('visibility', 'hidden');
				}
				if (self.resizeType === 2) {
					_drag({
						moveEl : container,
						clickEl : statusbar.last(),
						moveFn : function(x, y, width, height, diffX, diffY) {
							width += diffX;
							height += diffY;
							self.resize(width, height);
						}
					});
				} else {
					statusbar.last().css('visibility', 'hidden');
				}
			}
			return self;
		},
		remove : function() {
			var self = this;
			if (!self.isCreated) {
				return self;
			}
			self.beforeRemove();
			self.srcElement.data('kindeditor', '');
			if (self.menu) {
				self.hideMenu();
			}
			_each(self.dialogs, function() {
				self.hideDialog();
			});
			K(document).unbind('mousedown', self._docMousedownFn);
			self.toolbar.remove();
			self.edit.remove();
			self.statusbar.last().unbind();
			self.statusbar.unbind();
			self.container.remove();
			self.container = self.toolbar = self.edit = self.menu = null;
			self.dialogs = [];
			self.isCreated = false;
			return self;
		},
		resize : function(width, height, updateProp) {
			var self = this;
			updateProp = _undef(updateProp, true);
			if (width) {
				if (!/%/.test(width)) {
					width = _removeUnit(width);
					width = width < self.minWidth ? self.minWidth : width;
				}
				self.container.css('width', _addUnit(width));
				if (updateProp) {
					self.width = _addUnit(width);
				}
			}
			if (height) {
				height = _removeUnit(height);
				editHeight = _removeUnit(height) - self.toolbar.div.height()
						- self.statusbar.height();
				editHeight = editHeight < self.minHeight ? self.minHeight
						: editHeight;
				self.edit.setHeight(editHeight);
				if (updateProp) {
					self.height = _addUnit(height);
				}
			}
			return self;
		},
		select : function() {
			this.isCreated && this.cmd.select();
			return this;
		},
		html : function(val) {
			var self = this;
			if (val === undefined) {
				return self.isCreated ? self.edit.html()
						: _elementVal(self.srcElement);
			}
			self.isCreated ? self.edit.html(val) : _elementVal(self.srcElement,
					val);
			if (self.isCreated) {
				self.cmd.selection();
			}
			return self;
		},
		fullHtml : function() {
			return this.isCreated ? this.edit.html(undefined, true) : '';
		},
		text : function(val) {
			var self = this;
			if (val === undefined) {
				return _trim(self.html().replace(/<(?!img|embed).*?>/ig, '')
						.replace(/&nbsp;/ig, ' '));
			} else {
				return self.html(_escape(val));
			}
		},
		isEmpty : function() {
			return _trim(this.text().replace(/\r\n|\n|\r/, '')) === '';
		},
		isDirty : function() {
			return _trim(this.initContent.replace(/\r\n|\n|\r|t/g, '')) !== _trim(this
					.html().replace(/\r\n|\n|\r|t/g, ''));
		},
		selectedHtml : function() {
			var val = this.isCreated ? this.cmd.range.html() : '';
			val = _removeBookmarkTag(_removeTempTag(val));
			return val;
		},
		count : function(mode) {
			var self = this;
			mode = (mode || 'html').toLowerCase();
			if (mode === 'html') {
				return self.html().length;
			}
			if (mode === 'text') {
				return self.text().replace(/<(?:img|embed).*?>/ig, 'K')
						.replace(/\r\n|\n|\r/g, '').length;
			}
			return 0;
		},
		exec : function(key) {
			key = key.toLowerCase();
			var self = this, cmd = self.cmd, changeFlag = _inArray(key,
					'selectall,copy,paste,print'.split(',')) < 0;
			if (changeFlag) {
				self.addBookmark(false);
			}
			cmd[key].apply(cmd, _toArray(arguments, 1));
			if (changeFlag) {
				self.updateState();
				self.addBookmark(false);
				if (self.options.afterChange) {
					self.options.afterChange.call(self);
				}
			}
			return self;
		},
		insertHtml : function(val, quickMode) {
			if (!this.isCreated) {
				return this;
			}
			val = this.beforeSetHtml(val);
			this.exec('inserthtml', val, quickMode);
			return this;
		},
		appendHtml : function(val) {
			this.html(this.html() + val);
			if (this.isCreated) {
				var cmd = this.cmd;
				cmd.range.selectNodeContents(cmd.doc.body).collapse(false);
				cmd.select();
			}
			return this;
		},
		sync : function() {
			_elementVal(this.srcElement, this.html());
			return this;
		},
		focus : function() {
			this.isCreated ? this.edit.focus() : this.srcElement[0].focus();
			return this;
		},
		blur : function() {
			this.isCreated ? this.edit.blur() : this.srcElement[0].blur();
			return this;
		},
		addBookmark : function(checkSize) {
			checkSize = _undef(checkSize, true);
			var self = this, edit = self.edit, body = edit.doc.body, html = _removeTempTag(body.innerHTML), bookmark;
			if (checkSize && self._undoStack.length > 0) {
				var prev = self._undoStack[self._undoStack.length - 1];
				if (Math
						.abs(html.length - _removeBookmarkTag(prev.html).length) < self.minChangeSize) {
					return self;
				}
			}
			if (edit.designMode && !self._firstAddBookmark) {
				var range = self.cmd.range;
				bookmark = range.createBookmark(true);
				bookmark.html = _removeTempTag(body.innerHTML);
				range.moveToBookmark(bookmark);
			} else {
				bookmark = {
					html : html
				};
			}
			self._firstAddBookmark = false;
			_addBookmarkToStack(self._undoStack, bookmark);
			return self;
		},
		undo : function() {
			return _undoToRedo.call(this, this._undoStack, this._redoStack);
		},
		redo : function() {
			return _undoToRedo.call(this, this._redoStack, this._undoStack);
		},
		fullscreen : function(bool) {
			this.fullscreenMode = (bool === undefined ? !this.fullscreenMode
					: bool);
			this.addBookmark(false);
			return this.remove().create();
		},
		readonly : function(isReadonly) {
			isReadonly = _undef(isReadonly, true);
			var self = this, edit = self.edit, doc = edit.doc;
			if (self.designMode) {
				self.toolbar.disableAll(isReadonly, []);
			} else {
				_each(self.noDisableItems, function() {
					self.toolbar[isReadonly ? 'disable' : 'enable'](this);
				});
			}
			if (_IE) {
				doc.body.contentEditable = !isReadonly;
			} else {
				doc.designMode = isReadonly ? 'off' : 'on';
			}
			edit.textarea[0].disabled = isReadonly;
		},
		createMenu : function(options) {
			var self = this, name = options.name, knode = self.toolbar
					.get(name), pos = knode.pos();
			options.x = pos.x;
			options.y = pos.y + knode.height();
			options.z = self.options.zIndex;
			options.shadowMode = _undef(options.shadowMode, self.shadowMode);
			if (options.selectedColor !== undefined) {
				options.cls = 'ke-colorpicker-' + self.themeType;
				options.noColor = self.lang('noColor');
				self.menu = _colorpicker(options);
			} else {
				options.cls = 'ke-menu-' + self.themeType;
				options.centerLineMode = false;
				self.menu = _menu(options);
			}
			return self.menu;
		},
		hideMenu : function() {
			this.menu.remove();
			this.menu = null;
			return this;
		},
		hideContextmenu : function() {
			this.contextmenu.remove();
			this.contextmenu = null;
			return this;
		},
		createDialog : function(options) {
			var self = this, name = options.name;
			options.z = self.options.zIndex;
			options.shadowMode = _undef(options.shadowMode, self.shadowMode);
			options.closeBtn = _undef(options.closeBtn, {
				name : self.lang('close'),
				click : function(e) {
					self.hideDialog();
					if (_IE && self.cmd) {
						self.cmd.select();
					}
				}
			});
			options.noBtn = _undef(options.noBtn, {
				name : self.lang(options.yesBtn ? 'no' : 'close'),
				click : function(e) {
					self.hideDialog();
					if (_IE && self.cmd) {
						self.cmd.select();
					}
				}
			});
			if (self.dialogAlignType != 'page') {
				options.alignEl = self.container;
			}
			options.cls = 'ke-dialog-' + self.themeType;
			if (self.dialogs.length > 0) {
				var firstDialog = self.dialogs[0], parentDialog = self.dialogs[self.dialogs.length - 1];
				firstDialog.setMaskIndex(parentDialog.z + 2);
				options.z = parentDialog.z + 3;
				options.showMask = false;
			}
			var dialog = _dialog(options);
			self.dialogs.push(dialog);
			return dialog;
		},
		hideDialog : function() {
			var self = this;
			if (self.dialogs.length > 0) {
				self.dialogs.pop().remove();
			}
			if (self.dialogs.length > 0) {
				var firstDialog = self.dialogs[0], parentDialog = self.dialogs[self.dialogs.length - 1];
				firstDialog.setMaskIndex(parentDialog.z - 1);
			}
			return self;
		},
		errorDialog : function(html) {
			var self = this;
			var dialog = self
					.createDialog({
						width : 750,
						title : self.lang('uploadError'),
						body : '<div style="padding:10px 20px;"><iframe frameborder="0" style="width:708px;height:400px;"></iframe></div>'
					});
			var iframe = K('iframe', dialog.div), doc = K.iframeDoc(iframe);
			doc.open();
			doc.write(html);
			doc.close();
			K(doc.body).css('background-color', '#FFF');
			iframe[0].contentWindow.focus();
			return self;
		}
	};
	function _editor(options) {
		return new KEditor(options);
	}
	_instances = [];
	function _create(expr, options) {
		options = options || {};
		options.basePath = _undef(options.basePath, K.basePath);
		options.themesPath = _undef(options.themesPath, options.basePath
				+ 'themes/');
		options.langPath = _undef(options.langPath, options.basePath + 'lang/');
		options.pluginsPath = _undef(options.pluginsPath, options.basePath
				+ 'plugins/');
		if (_undef(options.loadStyleMode, K.options.loadStyleMode)) {
			var themeType = _undef(options.themeType, K.options.themeType);
			_loadStyle(options.themesPath + 'default/default.css');
			_loadStyle(options.themesPath + themeType + '/' + themeType
					+ '.css');
		}
		function create(editor) {
			_each(_plugins, function(name, fn) {
				if (_isFunction(fn)) {
					fn.call(editor, KindEditor);
				}
			});
			return editor.create();
		}
		var knode = K(expr);
		if (!knode || knode.length === 0) {
			return;
		}
		if (knode.length > 1) {
			knode.each(function() {
				_create(this, options);
			});
			return _instances[0];
		}
		options.srcElement = knode[0];
		var editor = new KEditor(options);
		_instances.push(editor);
		if (_language[editor.langType]) {
			return create(editor);
		}
		_loadScript(editor.langPath + editor.langType + '.js?ver='
				+ encodeURIComponent(K.DEBUG ? _TIME : _VERSION), function() {
			create(editor);
		});
		return editor;
	}
	function _eachEditor(expr, fn) {
		K(expr).each(function(i, el) {
			K.each(_instances, function(j, editor) {
				if (editor && editor.srcElement[0] == el) {
					fn.call(editor, j);
					return false;
				}
			});
		});
	}
	K.remove = function(expr) {
		_eachEditor(expr, function(i) {
			this.remove();
			_instances.splice(i, 1);
		});
	};
	K.sync = function(expr) {
		_eachEditor(expr, function() {
			this.sync();
		});
	};
	K.html = function(expr, val) {
		_eachEditor(expr, function() {
			this.html(val);
		});
	};
	K.insertHtml = function(expr, val) {
		_eachEditor(expr, function() {
			this.insertHtml(val);
		});
	};
	K.appendHtml = function(expr, val) {
		_eachEditor(expr, function() {
			this.appendHtml(val);
		});
	};
	if (_IE && _V < 7) {
		_nativeCommand(document, 'BackgroundImageCache', true);
	}
	K.EditorClass = KEditor;
	K.editor = _editor;
	K.create = _create;
	K.instances = _instances;
	K.plugin = _plugin;
	K.lang = _lang;
	_plugin(
			'core',
			function(K) {
				var self = this, shortcutKeys = {
					undo : 'Z',
					redo : 'Y',
					bold : 'B',
					italic : 'I',
					underline : 'U',
					print : 'P',
					selectall : 'A'
				};
				self.afterSetHtml(function() {
					if (self.options.afterChange) {
						self.options.afterChange.call(self);
					}
				});
				self.afterCreate(function() {
					if (self.syncType != 'form') {
						return;
					}
					var el = K(self.srcElement), hasForm = false;
					while ((el = el.parent())) {
						if (el.name == 'form') {
							hasForm = true;
							break;
						}
					}
					if (hasForm) {
						el.bind('submit', function(e) {
							self.sync();
							K(window).bind('unload', function() {
								self.edit.textarea.remove();
							});
						});
						var resetBtn = K('[type="reset"]', el);
						resetBtn.click(function() {
							self.html(self.initContent);
							self.cmd.selection();
						});
						self.beforeRemove(function() {
							el.unbind();
							resetBtn.unbind();
						});
					}
				});
				self.clickToolbar('source', function() {
					if (self.edit.designMode) {
						self.toolbar.disableAll(true);
						self.edit.design(false);
						self.toolbar.select('source');
					} else {
						self.toolbar.disableAll(false);
						self.edit.design(true);
						self.toolbar.unselect('source');
						if (_GECKO) {
							setTimeout(function() {
								self.cmd.selection();
							}, 0);
						} else {
							self.cmd.selection();
						}
					}
					self.designMode = self.edit.designMode;
				});
				self.afterCreate(function() {
					if (!self.designMode) {
						self.toolbar.disableAll(true).select('source');
					}
				});
				self.clickToolbar('fullscreen', function() {
					self.fullscreen();
				});
				if (self.fullscreenShortcut) {
					var loaded = false;
					self.afterCreate(function() {
						K(self.edit.doc, self.edit.textarea).keyup(function(e) {
							if (e.which == 27) {
								setTimeout(function() {
									self.fullscreen();
								}, 0);
							}
						});
						if (loaded) {
							if (_IE && !self.designMode) {
								return;
							}
							self.focus();
						}
						if (!loaded) {
							loaded = true;
						}
					});
				}
				_each('undo,redo'.split(','), function(i, name) {
					if (shortcutKeys[name]) {
						self.afterCreate(function() {
							_ctrl(this.edit.doc, shortcutKeys[name],
									function() {
										self.clickToolbar(name);
									});
						});
					}
					self.clickToolbar(name, function() {
						self[name]();
					});
				});
				self
						.clickToolbar(
								'formatblock',
								function() {
									var blocks = self
											.lang('formatblock.formatBlock'), heights = {
										h1 : 28,
										h2 : 24,
										h3 : 18,
										H4 : 14,
										p : 12
									}, curVal = self.cmd.val('formatblock'), menu = self
											.createMenu({
												name : 'formatblock',
												width : self.langType == 'en' ? 200
														: 150
											});
									_each(
											blocks,
											function(key, val) {
												var style = 'font-size:'
														+ heights[key] + 'px;';
												if (key.charAt(0) === 'h') {
													style += 'font-weight:bold;';
												}
												menu
														.addItem({
															title : '<span style="'
																	+ style
																	+ '" unselectable="on">'
																	+ val
																	+ '</span>',
															height : heights[key] + 12,
															checked : (curVal === key || curVal === val),
															click : function() {
																self
																		.select()
																		.exec(
																				'formatblock',
																				'<'
																						+ key
																						+ '>')
																		.hideMenu();
															}
														});
											});
								});
				self
						.clickToolbar(
								'fontname',
								function() {
									var curVal = self.cmd.val('fontname'), menu = self
											.createMenu({
												name : 'fontname',
												width : 150
											});
									_each(
											self.lang('fontname.fontName'),
											function(key, val) {
												menu
														.addItem({
															title : '<span style="font-family: '
																	+ key
																	+ ';" unselectable="on">'
																	+ val
																	+ '</span>',
															checked : (curVal === key
																	.toLowerCase() || curVal === val
																	.toLowerCase()),
															click : function() {
																self
																		.exec(
																				'fontname',
																				key)
																		.hideMenu();
															}
														});
											});
								});
				self.clickToolbar('fontsize', function() {
					var curVal = self.cmd.val('fontsize'), menu = self
							.createMenu({
								name : 'fontsize',
								width : 150
							});
					_each(self.fontSizeTable, function(i, val) {
						menu
								.addItem({
									title : '<span style="font-size:' + val
											+ ';" unselectable="on">' + val
											+ '</span>',
									height : _removeUnit(val) + 12,
									checked : curVal === val,
									click : function() {
										self.exec('fontsize', val).hideMenu();
									}
								});
					});
				});
				_each('forecolor,hilitecolor'.split(','), function(i, name) {
					self.clickToolbar(name, function() {
						self.createMenu({
							name : name,
							selectedColor : self.cmd.val(name) || 'default',
							colors : self.colorTable,
							click : function(color) {
								self.exec(name, color).hideMenu();
							}
						});
					});
				});
				_each(('cut,copy,paste').split(','), function(i, name) {
					self.clickToolbar(name, function() {
						self.focus();
						try {
							self.exec(name, null);
						} catch (e) {
							alert(self.lang(name + 'Error'));
						}
					});
				});
				self
						.clickToolbar(
								'about',
								function() {
									var html = '<div style="margin:20px;">'
											+ '<div>KindEditor '
											+ _VERSION
											+ '</div>'
											+ '<div>Copyright &copy; <a href="http://www.kindsoft.net/" target="_blank">kindsoft.net</a> All rights reserved.</div>'
											+ '</div>';
									self.createDialog({
										name : 'about',
										width : 350,
										title : self.lang('about'),
										body : html
									});
								});
				self.plugin.getSelectedLink = function() {
					return self.cmd.commonAncestor('a');
				};
				self.plugin.getSelectedImage = function() {
					return _getImageFromRange(self.edit.cmd.range,
							function(img) {
								return !/^ke-\w+$/i.test(img[0].className);
							});
				};
				self.plugin.getSelectedFlash = function() {
					return _getImageFromRange(self.edit.cmd.range,
							function(img) {
								return img[0].className == 'ke-flash';
							});
				};
				self.plugin.getSelectedMedia = function() {
					return _getImageFromRange(self.edit.cmd.range,
							function(img) {
								return img[0].className == 'ke-media'
										|| img[0].className == 'ke-rm';
							});
				};
				self.plugin.getSelectedAnchor = function() {
					return _getImageFromRange(self.edit.cmd.range,
							function(img) {
								return img[0].className == 'ke-anchor';
							});
				};
				_each('link,image,flash,media,anchor'.split(','), function(i,
						name) {
					var uName = name.charAt(0).toUpperCase() + name.substr(1);
					_each('edit,delete'.split(','), function(j, val) {
						self.addContextmenu({
							title : self.lang(val + uName),
							click : function() {
								self.loadPlugin(name, function() {
									self.plugin[name][val]();
									self.hideMenu();
								});
							},
							cond : self.plugin['getSelected' + uName],
							width : 150,
							iconClass : val == 'edit' ? 'ke-icon-' + name
									: undefined
						});
					});
					self.addContextmenu({
						title : '-'
					});
				});
				self.plugin.getSelectedTable = function() {
					return self.cmd.commonAncestor('table');
				};
				self.plugin.getSelectedRow = function() {
					return self.cmd.commonAncestor('tr');
				};
				self.plugin.getSelectedCell = function() {
					return self.cmd.commonAncestor('td');
				};
				_each(
						('prop,cellprop,colinsertleft,colinsertright,rowinsertabove,rowinsertbelow,rowmerge,colmerge,'
								+ 'rowsplit,colsplit,coldelete,rowdelete,insert,delete')
								.split(','),
						function(i, val) {
							var cond = _inArray(val, [ 'prop', 'delete' ]) < 0 ? self.plugin.getSelectedCell
									: self.plugin.getSelectedTable;
							self.addContextmenu({
								title : self.lang('table' + val),
								click : function() {
									self.loadPlugin('table', function() {
										self.plugin.table[val]();
										self.hideMenu();
									});
								},
								cond : cond,
								width : 170,
								iconClass : 'ke-icon-table' + val
							});
						});
				self.addContextmenu({
					title : '-'
				});
				_each(
						('selectall,justifyleft,justifycenter,justifyright,justifyfull,insertorderedlist,'
								+ 'insertunorderedlist,indent,outdent,subscript,superscript,hr,print,'
								+ 'bold,italic,underline,strikethrough,removeformat,unlink')
								.split(','), function(i, name) {
							if (shortcutKeys[name]) {
								self.afterCreate(function() {
									_ctrl(this.edit.doc, shortcutKeys[name],
											function() {
												self.cmd.selection();
												self.clickToolbar(name);
											});
								});
							}
							self.clickToolbar(name, function() {
								self.focus().exec(name, null);
							});
						});
				self
						.afterCreate(function() {
							var doc = self.edit.doc, cmd, bookmark, div, cls = '__kindeditor_paste__', pasting = false;
							function movePastedData() {
								cmd.range.moveToBookmark(bookmark);
								cmd.select();
								if (_WEBKIT) {
									K('div.' + cls, div).each(function() {
										K(this).after('<br />').remove(true);
									});
									K('span.Apple-style-span', div)
											.remove(true);
									K('span.Apple-tab-span', div).remove(true);
									K('span[style]', div)
											.each(
													function() {
														if (K(this).css(
																'white-space') == 'nowrap') {
															K(this)
																	.remove(
																			true);
														}
													});
									K('meta', div).remove();
								}
								var html = div[0].innerHTML;
								div.remove();
								if (html === '') {
									return;
								}
								if (_WEBKIT) {
									html = html.replace(/(<br>)\1/ig, '$1');
								}
								if (self.pasteType === 2) {
									html = html
											.replace(
													/(<(?:p|p\s[^>]*)>) *(<\/p>)/ig,
													'');
									if (/schemas-microsoft-com|worddocument|mso-\w+/i
											.test(html)) {
										html = _clearMsWord(html,
												self.filterMode ? self.htmlTags
														: K.options.htmlTags);
									} else {
										html = _formatHtml(html,
												self.filterMode ? self.htmlTags
														: null);
										html = self.beforeSetHtml(html);
									}
								}
								if (self.pasteType === 1) {
									html = html.replace(/&nbsp;/ig, ' ');
									html = html.replace(/\n\s*\n/g, '\n');
									html = html.replace(/<br[^>]*>/ig, '\n');
									html = html
											.replace(/<\/p><p[^>]*>/ig, '\n');
									html = html.replace(/<[^>]+>/g, '');
									html = html.replace(/ {2}/g, ' &nbsp;');
									if (self.newlineTag == 'p') {
										if (/\n/.test(html)) {
											html = html.replace(/^/, '<p>')
													.replace(/$/, '<br /></p>')
													.replace(/\n/g,
															'<br /></p><p>');
										}
									} else {
										html = html.replace(/\n/g, '<br />$&');
									}
								}
								self.insertHtml(html, true);
							}
							K(doc.body)
									.bind(
											'paste',
											function(e) {
												if (self.pasteType === 0) {
													e.stop();
													return;
												}
												if (pasting) {
													return;
												}
												pasting = true;
												K('div.' + cls, doc).remove();
												cmd = self.cmd.selection();
												bookmark = cmd.range
														.createBookmark();
												div = K(
														'<div class="' + cls
																+ '"></div>',
														doc)
														.css(
																{
																	position : 'absolute',
																	width : '1px',
																	height : '1px',
																	overflow : 'hidden',
																	left : '-1981px',
																	top : K(
																			bookmark.start)
																			.pos().y
																			+ 'px',
																	'white-space' : 'nowrap'
																});
												K(doc.body).append(div);
												if (_IE) {
													var rng = cmd.range
															.get(true);
													rng
															.moveToElementText(div[0]);
													rng.select();
													rng.execCommand('paste');
													e.preventDefault();
												} else {
													cmd.range
															.selectNodeContents(div[0]);
													cmd.select();
												}
												setTimeout(function() {
													movePastedData();
													pasting = false;
												}, 0);
											});
						});
				self
						.beforeGetHtml(function(html) {
							if (_IE && _V <= 8) {
								html = html
										.replace(
												/<div\s+[^>]*data-ke-input-tag="([^"]*)"[^>]*>([\s\S]*?)<\/div>/ig,
												function(full, tag) {
													return unescape(tag);
												});
								html = html
										.replace(
												/(<input)((?:\s+[^>]*)?>)/ig,
												function($0, $1, $2) {
													if (!/\s+type="[^"]+"/i
															.test($0)) {
														return $1
																+ ' type="text"'
																+ $2;
													}
													return $0;
												});
							}
							return html
									.replace(
											/(<(?:noscript|noscript\s[^>]*)>)([\s\S]*?)(<\/noscript>)/ig,
											function($0, $1, $2, $3) {
												return $1
														+ _unescape($2)
																.replace(
																		/\s+/g,
																		' ')
														+ $3;
											})
									.replace(
											/<img[^>]*class="?ke-(flash|rm|media)"?[^>]*>/ig,
											function(full) {
												var imgAttrs = _getAttrList(full);
												var styles = _getCssList(imgAttrs.style
														|| '');
												var attrs = _mediaAttrs(imgAttrs['data-ke-tag']);
												var width = _undef(
														styles.width, '');
												var height = _undef(
														styles.height, '');
												if (/px/i.test(width)) {
													width = _removeUnit(width);
												}
												if (/px/i.test(height)) {
													height = _removeUnit(height);
												}
												attrs.width = _undef(
														imgAttrs.width, width);
												attrs.height = _undef(
														imgAttrs.height, height);
												return _mediaEmbed(attrs);
											})
									.replace(
											/<img[^>]*class="?ke-anchor"?[^>]*>/ig,
											function(full) {
												var imgAttrs = _getAttrList(full);
												return '<a name="'
														+ unescape(imgAttrs['data-ke-name'])
														+ '"></a>';
											})
									.replace(
											/<div\s+[^>]*data-ke-script-attr="([^"]*)"[^>]*>([\s\S]*?)<\/div>/ig,
											function(full, attr, code) {
												return '<script'
														+ unescape(attr) + '>'
														+ unescape(code)
														+ '</script>';
											})
									.replace(
											/<div\s+[^>]*data-ke-noscript-attr="([^"]*)"[^>]*>([\s\S]*?)<\/div>/ig,
											function(full, attr, code) {
												return '<noscript'
														+ unescape(attr) + '>'
														+ unescape(code)
														+ '</noscript>';
											})
									.replace(
											/(<[^>]*)data-ke-src="([^"]*)"([^>]*>)/ig,
											function(full, start, src, end) {
												full = full
														.replace(
																/(\s+(?:href|src)=")[^"]*(")/i,
																function($0,
																		$1, $2) {
																	return $1
																			+ _unescape(src)
																			+ $2;
																});
												full = full
														.replace(
																/\s+data-ke-src="[^"]*"/i,
																'');
												return full;
											})
									.replace(
											/(<[^>]+\s)data-ke-(on\w+="[^"]*"[^>]*>)/ig,
											function(full, start, end) {
												return start + end;
											});
						});
				self
						.beforeSetHtml(function(html) {
							if (_IE && _V <= 8) {
								html = html
										.replace(
												/<input[^>]*>|<(select|button)[^>]*>[\s\S]*?<\/\1>/ig,
												function(full) {
													var attrs = _getAttrList(full);
													var styles = _getCssList(attrs.style
															|| '');
													if (styles.display == 'none') {
														return '<div class="ke-display-none" data-ke-input-tag="'
																+ escape(full)
																+ '"></div>';
													}
													return full;
												});
							}
							return html
									.replace(
											/<embed[^>]*type="([^"]+)"[^>]*>(?:<\/embed>)?/ig,
											function(full) {
												var attrs = _getAttrList(full);
												attrs.src = _undef(attrs.src,
														'');
												attrs.width = _undef(
														attrs.width, 0);
												attrs.height = _undef(
														attrs.height, 0);
												return _mediaImg(
														self.themesPath
																+ 'common/blank.gif',
														attrs);
											})
									.replace(
											/<a[^>]*name="([^"]+)"[^>]*>(?:<\/a>)?/ig,
											function(full) {
												var attrs = _getAttrList(full);
												if (attrs.href !== undefined) {
													return full;
												}
												return '<img class="ke-anchor" src="'
														+ self.themesPath
														+ 'common/anchor.gif" data-ke-name="'
														+ escape(attrs.name)
														+ '" />';
											})
									.replace(
											/<script([^>]*)>([\s\S]*?)<\/script>/ig,
											function(full, attr, code) {
												return '<div class="ke-script" data-ke-script-attr="'
														+ escape(attr)
														+ '">'
														+ escape(code)
														+ '</div>';
											})
									.replace(
											/<noscript([^>]*)>([\s\S]*?)<\/noscript>/ig,
											function(full, attr, code) {
												return '<div class="ke-noscript" data-ke-noscript-attr="'
														+ escape(attr)
														+ '">'
														+ escape(code)
														+ '</div>';
											})
									.replace(
											/(<[^>]*)(href|src)="([^"]*)"([^>]*>)/ig,
											function(full, start, key, src, end) {
												if (full
														.match(/\sdata-ke-src="[^"]*"/i)) {
													return full;
												}
												full = start + key + '="' + src
														+ '"'
														+ ' data-ke-src="'
														+ _escape(src) + '"'
														+ end;
												return full;
											})
									.replace(
											/(<[^>]+\s)(on\w+="[^"]*"[^>]*>)/ig,
											function(full, start, end) {
												return start + 'data-ke-' + end;
											})
									.replace(
											/<table[^>]*\s+border="0"[^>]*>/ig,
											function(full) {
												if (full
														.indexOf('ke-zeroborder') >= 0) {
													return full;
												}
												return _addClassToTag(full,
														'ke-zeroborder');
											});
						});
			});
})(window);
